<commit_before>#![deny(warnings)]

use std::env;

use actix_cors::Cors;
use actix_web::{http::header, middleware, web, App, Error, HttpResponse, HttpServer};
use juniper::{
    tests::fixtures::starwars::schema::{Database, Query},
    EmptyMutation, EmptySubscription, RootNode,
};
use juniper_actix::{
    graphiql_handler as gqli_handler, graphql_handler, playground_handler as play_handler,
};

type Schema = RootNode<'static, Query, EmptyMutation<Database>, EmptySubscription<Database>>;

fn schema() -> Schema {
    Schema::new(
        Query,
        EmptyMutation::<Database>::new(),
        EmptySubscription::<Database>::new(),
    )
}

async fn graphiql_handler() -> Result<HttpResponse, Error> {
    gqli_handler("/", None).await
}
async fn playground_handler() -> Result<HttpResponse, Error> {
    play_handler("/", None).await
}
async fn graphql(
    req: actix_web::HttpRequest,
    payload: actix_web::web::Payload,
    schema: web::Data<Schema>,
) -> Result<HttpResponse, Error> {
    let context = Database::new();
    graphql_handler(&schema, &context, req, payload).await
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    env::set_var("RUST_LOG", "info");
    env_logger::init();

    let server = HttpServer::new(move || {
        App::new()
            .data(schema())
            .wrap(middleware::Compress::default())
            .wrap(middleware::Logger::default())
            .wrap(
                Cors::default()
                    .allowed_origin("http://127.0.0.1:8080")
                    .allowed_methods(vec!["POST", "GET"])
                    .allowed_headers(vec![header::AUTHORIZATION, header::ACCEPT])
                    .allowed_header(header::CONTENT_TYPE)
                    .supports_credentials()
                    .max_age(3600),
            )
            .service(
                web::resource("/")
                    .route(web::post().to(graphql))
                    .route(web::get().to(graphql)),
            )
            .service(web::resource("/playground").route(web::get().to(playground_handler)))
            .service(web::resource("/graphiql").route(web::get().to(graphiql_handler)))
    });
    server.bind("127.0.0.1:8080").unwrap().run().await
}
<commit_msg>Make the actix example self contained (#839)<commit_after>#![deny(warnings)]

use std::{collections::HashMap, env};

use actix_cors::Cors;
use actix_web::{http::header, middleware, web, App, Error, HttpResponse, HttpServer};
use juniper::{graphql_object, EmptyMutation, EmptySubscription, GraphQLObject, RootNode};
use juniper_actix::{graphiql_handler, graphql_handler, playground_handler};
#[derive(Clone, GraphQLObject)]
///a user
pub struct User {
    ///the id
    id: i32,
    ///the name
    name: String,
}

#[derive(Default, Clone)]
pub struct Database {
    ///this could be a database connection
    users: HashMap<i32, User>,
}
impl Database {
    pub fn new() -> Database {
        let mut users = HashMap::new();
        users.insert(
            1,
            User {
                id: 1,
                name: "Aron".to_string(),
            },
        );
        users.insert(
            2,
            User {
                id: 2,
                name: "Bea".to_string(),
            },
        );
        users.insert(
            3,
            User {
                id: 3,
                name: "Carl".to_string(),
            },
        );
        users.insert(
            4,
            User {
                id: 4,
                name: "Dora".to_string(),
            },
        );
        Database { users }
    }
    pub fn get_user(&self, id: &i32) -> Option<&User> {
        self.users.get(id)
    }
}

// To make our Database usable by Juniper, we have to implement a marker trait.
impl juniper::Context for Database {}

// Queries represent the callable funcitons
struct Query;
#[graphql_object(context = Database)]
impl Query {
    fn apiVersion() -> String {
        "1.0".to_string()
    }
    #[graphql(arguments(id(description = "id of the user")))]
    fn user(database: &Database, id: i32) -> Option<&User> {
        database.get_user(&id)
    }
}

type Schema = RootNode<'static, Query, EmptyMutation<Database>, EmptySubscription<Database>>;

fn schema() -> Schema {
    Schema::new(
        Query,
        EmptyMutation::<Database>::new(),
        EmptySubscription::<Database>::new(),
    )
}

async fn graphiql_route() -> Result<HttpResponse, Error> {
    graphiql_handler("/graphgl", None).await
}
async fn playground_route() -> Result<HttpResponse, Error> {
    playground_handler("/graphgl", None).await
}
async fn graphql_route(
    req: actix_web::HttpRequest,
    payload: actix_web::web::Payload,
    schema: web::Data<Schema>,
) -> Result<HttpResponse, Error> {
    let context = Database::new();
    graphql_handler(&schema, &context, req, payload).await
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    env::set_var("RUST_LOG", "info");
    env_logger::init();

    let server = HttpServer::new(move || {
        App::new()
            .data(schema())
            .wrap(middleware::Compress::default())
            .wrap(middleware::Logger::default())
            .wrap(
                Cors::default()
                    .allowed_origin("http://127.0.0.1:8080")
                    .allowed_methods(vec!["POST", "GET"])
                    .allowed_headers(vec![header::AUTHORIZATION, header::ACCEPT])
                    .allowed_header(header::CONTENT_TYPE)
                    .supports_credentials()
                    .max_age(3600),
            )
            .service(
                web::resource("/graphgl")
                    .route(web::post().to(graphql_route))
                    .route(web::get().to(graphql_route)),
            )
            .service(web::resource("/playground").route(web::get().to(playground_route)))
            .service(web::resource("/graphiql").route(web::get().to(graphiql_route)))
    });
    server.bind("127.0.0.1:8080").unwrap().run().await
}
// now go to http://127.0.0.1:8080/playground or graphiql and execute
//{  apiVersion,  user(id: 2){id, name}}
<|endoftext|>


<commit_before>// pest. The Elegant Parser
// Copyright (c) 2018 Dragoș Tiselice
//
// 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. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

use ast::*;

pub fn rotate(rule: Rule) -> Rule {
    match rule {
        Rule { name, ty, expr } => Rule {
            name,
            ty,
            // TODO: Use box syntax when it gets stabilized.
            expr: expr.map_bottom_up(|expr| match expr {
                Expr::Seq(lhs, rhs) => {
                    let lhs = *lhs;
                    match lhs {
                        Expr::Seq(ll, lr) => Expr::Seq(ll, Box::new(Expr::Seq(lr, rhs))),
                        lhs => Expr::Seq(Box::new(lhs), rhs)
                    }
                }
                Expr::Choice(lhs, rhs) => {
                    let lhs = *lhs;
                    match lhs {
                        Expr::Choice(ll, lr) => {
                            Expr::Choice(ll, Box::new(Expr::Choice(lr, rhs)))
                        }
                        lhs => Expr::Choice(Box::new(lhs), rhs)
                    }
                }
                expr => expr
            })
        }
    }
}
<commit_msg>Fixed rotater.<commit_after>// pest. The Elegant Parser
// Copyright (c) 2018 Dragoș Tiselice
//
// 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. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

use ast::*;

pub fn rotate(rule: Rule) -> Rule {
    fn rotate_internal(expr: Expr) -> Expr {
        match expr {
            // TODO: Use box syntax when it gets stabilized.
            Expr::Seq(lhs, rhs) => {
                let lhs = *lhs;
                match lhs {
                    Expr::Seq(ll, lr) => {
                        rotate_internal(Expr::Seq(ll, Box::new(Expr::Seq(lr, rhs))))
                    },
                    lhs => Expr::Seq(Box::new(lhs), rhs)
                }
            }
            Expr::Choice(lhs, rhs) => {
                let lhs = *lhs;
                match lhs {
                    Expr::Choice(ll, lr) => {
                        rotate_internal(Expr::Choice(ll, Box::new(Expr::Choice(lr, rhs))))
                    }
                    lhs => Expr::Choice(Box::new(lhs), rhs)
                }
            }
            expr => expr
        }
    }

    match rule {
        Rule { name, ty, expr } => Rule {
            name,
            ty,
            expr: expr.map_top_down(rotate_internal)
        }
    }
}
<|endoftext|>


<commit_before>use hir::def_id::DefId;
use hir::HirId;
use hir::ItemKind;
use rustc_ast::Mutability;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_middle::ty::subst::InternalSubsts;
use rustc_middle::ty::{Adt, Array, Ref, Ty};
use rustc_session::lint::builtin::RUST_2021_PRELUDE_COLLISIONS;
use rustc_span::symbol::kw::{Empty, Underscore};
use rustc_span::symbol::{sym, Ident};
use rustc_span::Span;
use rustc_trait_selection::infer::InferCtxtExt;

use crate::check::{
    method::probe::{self, Pick},
    FnCtxt,
};

impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
    pub(super) fn lint_dot_call_from_2018(
        &self,
        self_ty: Ty<'tcx>,
        segment: &hir::PathSegment<'_>,
        span: Span,
        call_expr: &'tcx hir::Expr<'tcx>,
        self_expr: &'tcx hir::Expr<'tcx>,
        pick: &Pick<'tcx>,
        args: &'tcx [hir::Expr<'tcx>],
    ) {
        debug!(
            "lookup(method_name={}, self_ty={:?}, call_expr={:?}, self_expr={:?})",
            segment.ident, self_ty, call_expr, self_expr
        );

        // Rust 2021 and later is already using the new prelude
        if span.rust_2021() {
            return;
        }

        let prelude_or_array_lint = match segment.ident.name {
            // `try_into` was added to the prelude in Rust 2021.
            sym::try_into => RUST_2021_PRELUDE_COLLISIONS,
            // `into_iter` wasn't added to the prelude,
            // but `[T; N].into_iter()` doesn't resolve to IntoIterator::into_iter
            // before Rust 2021, which results in the same problem.
            // It is only a problem for arrays.
            sym::into_iter if let Array(..) = self_ty.kind() => {
                // In this case, it wasn't really a prelude addition that was the problem.
                // Instead, the problem is that the array-into_iter hack will no longer apply in Rust 2021.
                rustc_lint::ARRAY_INTO_ITER
            }
            _ => return,
        };

        // No need to lint if method came from std/core, as that will now be in the prelude
        if matches!(self.tcx.crate_name(pick.item.def_id.krate), sym::std | sym::core) {
            return;
        }

        if matches!(pick.kind, probe::PickKind::InherentImplPick | probe::PickKind::ObjectPick) {
            // avoid repeatedly adding unneeded `&*`s
            if pick.autoderefs == 1
                && matches!(
                    pick.autoref_or_ptr_adjustment,
                    Some(probe::AutorefOrPtrAdjustment::Autoref { .. })
                )
                && matches!(self_ty.kind(), Ref(..))
            {
                return;
            }

            // if it's an inherent `self` method (not `&self` or `&mut self`), it will take
            // precedence over the `TryInto` impl, and thus won't break in 2021 edition
            if pick.autoderefs == 0 && pick.autoref_or_ptr_adjustment.is_none() {
                return;
            }

            // Inherent impls only require not relying on autoref and autoderef in order to
            // ensure that the trait implementation won't be used
            self.tcx.struct_span_lint_hir(
                prelude_or_array_lint,
                self_expr.hir_id,
                self_expr.span,
                |lint| {
                    let sp = self_expr.span;

                    let mut lint = lint.build(&format!(
                        "trait method `{}` will become ambiguous in Rust 2021",
                        segment.ident.name
                    ));

                    let derefs = "*".repeat(pick.autoderefs);

                    let autoref = match pick.autoref_or_ptr_adjustment {
                        Some(probe::AutorefOrPtrAdjustment::Autoref {
                            mutbl: Mutability::Mut,
                            ..
                        }) => "&mut ",
                        Some(probe::AutorefOrPtrAdjustment::Autoref {
                            mutbl: Mutability::Not,
                            ..
                        }) => "&",
                        Some(probe::AutorefOrPtrAdjustment::ToConstPtr) | None => "",
                    };
                    if let Ok(self_expr) = self.sess().source_map().span_to_snippet(self_expr.span)
                    {
                        let self_adjusted = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) =
                            pick.autoref_or_ptr_adjustment
                        {
                            format!("{}{} as *const _", derefs, self_expr)
                        } else {
                            format!("{}{}{}", autoref, derefs, self_expr)
                        };

                        lint.span_suggestion(
                            sp,
                            "disambiguate the method call",
                            format!("({})", self_adjusted),
                            Applicability::MachineApplicable,
                        );
                    } else {
                        let self_adjusted = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) =
                            pick.autoref_or_ptr_adjustment
                        {
                            format!("{}(...) as *const _", derefs)
                        } else {
                            format!("{}{}...", autoref, derefs)
                        };
                        lint.span_help(
                            sp,
                            &format!("disambiguate the method call with `({})`", self_adjusted,),
                        );
                    }

                    lint.emit();
                },
            );
        } else {
            // trait implementations require full disambiguation to not clash with the new prelude
            // additions (i.e. convert from dot-call to fully-qualified call)
            self.tcx.struct_span_lint_hir(
                prelude_or_array_lint,
                call_expr.hir_id,
                call_expr.span,
                |lint| {
                    let sp = call_expr.span;
                    let trait_name = self.trait_path_or_bare_name(
                        span,
                        call_expr.hir_id,
                        pick.item.container.id(),
                    );

                    let mut lint = lint.build(&format!(
                        "trait method `{}` will become ambiguous in Rust 2021",
                        segment.ident.name
                    ));

                    let (self_adjusted, precise) = self.adjust_expr(pick, self_expr);
                    if precise {
                        let args = args
                            .iter()
                            .skip(1)
                            .map(|arg| {
                                format!(
                                    ", {}",
                                    self.sess().source_map().span_to_snippet(arg.span).unwrap()
                                )
                            })
                            .collect::<String>();

                        lint.span_suggestion(
                            sp,
                            "disambiguate the associated function",
                            format!(
                                "{}::{}({}{})",
                                trait_name, segment.ident.name, self_adjusted, args
                            ),
                            Applicability::MachineApplicable,
                        );
                    } else {
                        lint.span_help(
                            sp,
                            &format!(
                                "disambiguate the associated function with `{}::{}(...)`",
                                trait_name, segment.ident,
                            ),
                        );
                    }

                    lint.emit();
                },
            );
        }
    }

    pub(super) fn lint_fully_qualified_call_from_2018(
        &self,
        span: Span,
        method_name: Ident,
        self_ty: Ty<'tcx>,
        self_ty_span: Span,
        expr_id: hir::HirId,
        pick: &Pick<'tcx>,
    ) {
        // Rust 2021 and later is already using the new prelude
        if span.rust_2021() {
            return;
        }

        // These are the fully qualified methods added to prelude in Rust 2021
        if !matches!(method_name.name, sym::try_into | sym::try_from | sym::from_iter) {
            return;
        }

        // No need to lint if method came from std/core, as that will now be in the prelude
        if matches!(self.tcx.crate_name(pick.item.def_id.krate), sym::std | sym::core) {
            return;
        }

        // For from_iter, check if the type actually implements FromIterator.
        // If we know it does not, we don't need to warn.
        if method_name.name == sym::from_iter {
            if let Some(trait_def_id) = self.tcx.get_diagnostic_item(sym::FromIterator) {
                if !self
                    .infcx
                    .type_implements_trait(
                        trait_def_id,
                        self_ty,
                        InternalSubsts::empty(),
                        self.param_env,
                    )
                    .may_apply()
                {
                    return;
                }
            }
        }

        // No need to lint if this is an inherent method called on a specific type, like `Vec::foo(...)`,
        // since such methods take precedence over trait methods.
        if matches!(pick.kind, probe::PickKind::InherentImplPick) {
            return;
        }

        self.tcx.struct_span_lint_hir(RUST_2021_PRELUDE_COLLISIONS, expr_id, span, |lint| {
            // "type" refers to either a type or, more likely, a trait from which
            // the associated function or method is from.
            let trait_path = self.trait_path_or_bare_name(span, expr_id, pick.item.container.id());
            let trait_generics = self.tcx.generics_of(pick.item.container.id());

            let trait_name =
                if trait_generics.params.len() <= trait_generics.has_self as usize {
                    trait_path
                } else {
                    let counts = trait_generics.own_counts();
                    format!(
                        "{}<{}>",
                        trait_path,
                        std::iter::repeat("'_")
                            .take(counts.lifetimes)
                            .chain(std::iter::repeat("_").take(
                                counts.types + counts.consts - trait_generics.has_self as usize
                            ))
                            .collect::<Vec<_>>()
                            .join(", ")
                    )
                };

            let mut lint = lint.build(&format!(
                "trait-associated function `{}` will become ambiguous in Rust 2021",
                method_name.name
            ));

            let mut self_ty_name = self
                .sess()
                .source_map()
                .span_to_snippet(self_ty_span)
                .unwrap_or_else(|_| self_ty.to_string());

            // Get the number of generics the self type has (if an Adt) unless we can determine that
            // the user has written the self type with generics already which we (naively) do by looking
            // for a "<" in `self_ty_name`.
            if !self_ty_name.contains('<') {
                if let Adt(def, _) = self_ty.kind() {
                    let generics = self.tcx.generics_of(def.did);
                    if !generics.params.is_empty() {
                        let counts = generics.own_counts();
                        self_ty_name += &format!(
                            "<{}>",
                            std::iter::repeat("'_")
                                .take(counts.lifetimes)
                                .chain(std::iter::repeat("_").take(counts.types + counts.consts))
                                .collect::<Vec<_>>()
                                .join(", ")
                        );
                    }
                }
            }
            lint.span_suggestion(
                span,
                "disambiguate the associated function",
                format!("<{} as {}>::{}", self_ty_name, trait_name, method_name.name,),
                Applicability::MachineApplicable,
            );

            lint.emit();
        });
    }

    fn trait_path_or_bare_name(
        &self,
        span: Span,
        expr_hir_id: HirId,
        trait_def_id: DefId,
    ) -> String {
        self.trait_path(span, expr_hir_id, trait_def_id).unwrap_or_else(|| {
            let key = self.tcx.def_key(trait_def_id);
            format!("{}", key.disambiguated_data.data)
        })
    }

    fn trait_path(&self, span: Span, expr_hir_id: HirId, trait_def_id: DefId) -> Option<String> {
        let applicable_traits = self.tcx.in_scope_traits(expr_hir_id)?;
        let applicable_trait = applicable_traits.iter().find(|t| t.def_id == trait_def_id)?;
        if applicable_trait.import_ids.is_empty() {
            // The trait was declared within the module, we only need to use its name.
            return None;
        }

        let import_items: Vec<_> = applicable_trait
            .import_ids
            .iter()
            .map(|&import_id| {
                let hir_id = self.tcx.hir().local_def_id_to_hir_id(import_id);
                self.tcx.hir().expect_item(hir_id)
            })
            .collect();

        // Find an identifier with which this trait was imported (note that `_` doesn't count).
        let any_id = import_items
            .iter()
            .filter_map(|item| if item.ident.name != Underscore { Some(item.ident) } else { None })
            .next();
        if let Some(any_id) = any_id {
            if any_id.name == Empty {
                // Glob import, so just use its name.
                return None;
            } else {
                return Some(format!("{}", any_id));
            }
        }

        // All that is left is `_`! We need to use the full path. It doesn't matter which one we pick,
        // so just take the first one.
        match import_items[0].kind {
            ItemKind::Use(path, _) => Some(
                path.segments
                    .iter()
                    .map(|segment| segment.ident.to_string())
                    .collect::<Vec<_>>()
                    .join("::"),
            ),
            _ => {
                span_bug!(span, "unexpected item kind, expected a use: {:?}", import_items[0].kind);
            }
        }
    }

    /// Creates a string version of the `expr` that includes explicit adjustments.
    /// Returns the string and also a bool indicating whther this is a *precise*
    /// suggestion.
    fn adjust_expr(&self, pick: &Pick<'tcx>, expr: &hir::Expr<'tcx>) -> (String, bool) {
        let derefs = "*".repeat(pick.autoderefs);

        let autoref = match pick.autoref_or_ptr_adjustment {
            Some(probe::AutorefOrPtrAdjustment::Autoref { mutbl: Mutability::Mut, .. }) => "&mut ",
            Some(probe::AutorefOrPtrAdjustment::Autoref { mutbl: Mutability::Not, .. }) => "&",
            Some(probe::AutorefOrPtrAdjustment::ToConstPtr) | None => "",
        };

        let (expr_text, precise) =
            if let Ok(expr_text) = self.sess().source_map().span_to_snippet(expr.span) {
                (expr_text, true)
            } else {
                ("(..)".to_string(), false)
            };

        let adjusted_text = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) =
            pick.autoref_or_ptr_adjustment
        {
            format!("{}{} as *const _", derefs, expr_text)
        } else {
            format!("{}{}{}", autoref, derefs, expr_text)
        };

        (adjusted_text, precise)
    }
}
<commit_msg>Use right span in prelude collision suggestions with macros.<commit_after>use hir::def_id::DefId;
use hir::HirId;
use hir::ItemKind;
use rustc_ast::Mutability;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_middle::ty::subst::InternalSubsts;
use rustc_middle::ty::{Adt, Array, Ref, Ty};
use rustc_session::lint::builtin::RUST_2021_PRELUDE_COLLISIONS;
use rustc_span::symbol::kw::{Empty, Underscore};
use rustc_span::symbol::{sym, Ident};
use rustc_span::Span;
use rustc_trait_selection::infer::InferCtxtExt;

use crate::check::{
    method::probe::{self, Pick},
    FnCtxt,
};

impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
    pub(super) fn lint_dot_call_from_2018(
        &self,
        self_ty: Ty<'tcx>,
        segment: &hir::PathSegment<'_>,
        span: Span,
        call_expr: &'tcx hir::Expr<'tcx>,
        self_expr: &'tcx hir::Expr<'tcx>,
        pick: &Pick<'tcx>,
        args: &'tcx [hir::Expr<'tcx>],
    ) {
        debug!(
            "lookup(method_name={}, self_ty={:?}, call_expr={:?}, self_expr={:?})",
            segment.ident, self_ty, call_expr, self_expr
        );

        // Rust 2021 and later is already using the new prelude
        if span.rust_2021() {
            return;
        }

        let prelude_or_array_lint = match segment.ident.name {
            // `try_into` was added to the prelude in Rust 2021.
            sym::try_into => RUST_2021_PRELUDE_COLLISIONS,
            // `into_iter` wasn't added to the prelude,
            // but `[T; N].into_iter()` doesn't resolve to IntoIterator::into_iter
            // before Rust 2021, which results in the same problem.
            // It is only a problem for arrays.
            sym::into_iter if let Array(..) = self_ty.kind() => {
                // In this case, it wasn't really a prelude addition that was the problem.
                // Instead, the problem is that the array-into_iter hack will no longer apply in Rust 2021.
                rustc_lint::ARRAY_INTO_ITER
            }
            _ => return,
        };

        // No need to lint if method came from std/core, as that will now be in the prelude
        if matches!(self.tcx.crate_name(pick.item.def_id.krate), sym::std | sym::core) {
            return;
        }

        if matches!(pick.kind, probe::PickKind::InherentImplPick | probe::PickKind::ObjectPick) {
            // avoid repeatedly adding unneeded `&*`s
            if pick.autoderefs == 1
                && matches!(
                    pick.autoref_or_ptr_adjustment,
                    Some(probe::AutorefOrPtrAdjustment::Autoref { .. })
                )
                && matches!(self_ty.kind(), Ref(..))
            {
                return;
            }

            // if it's an inherent `self` method (not `&self` or `&mut self`), it will take
            // precedence over the `TryInto` impl, and thus won't break in 2021 edition
            if pick.autoderefs == 0 && pick.autoref_or_ptr_adjustment.is_none() {
                return;
            }

            // Inherent impls only require not relying on autoref and autoderef in order to
            // ensure that the trait implementation won't be used
            self.tcx.struct_span_lint_hir(
                prelude_or_array_lint,
                self_expr.hir_id,
                self_expr.span,
                |lint| {
                    let sp = self_expr.span;

                    let mut lint = lint.build(&format!(
                        "trait method `{}` will become ambiguous in Rust 2021",
                        segment.ident.name
                    ));

                    let derefs = "*".repeat(pick.autoderefs);

                    let autoref = match pick.autoref_or_ptr_adjustment {
                        Some(probe::AutorefOrPtrAdjustment::Autoref {
                            mutbl: Mutability::Mut,
                            ..
                        }) => "&mut ",
                        Some(probe::AutorefOrPtrAdjustment::Autoref {
                            mutbl: Mutability::Not,
                            ..
                        }) => "&",
                        Some(probe::AutorefOrPtrAdjustment::ToConstPtr) | None => "",
                    };
                    if let Ok(self_expr) = self.sess().source_map().span_to_snippet(self_expr.span)
                    {
                        let self_adjusted = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) =
                            pick.autoref_or_ptr_adjustment
                        {
                            format!("{}{} as *const _", derefs, self_expr)
                        } else {
                            format!("{}{}{}", autoref, derefs, self_expr)
                        };

                        lint.span_suggestion(
                            sp,
                            "disambiguate the method call",
                            format!("({})", self_adjusted),
                            Applicability::MachineApplicable,
                        );
                    } else {
                        let self_adjusted = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) =
                            pick.autoref_or_ptr_adjustment
                        {
                            format!("{}(...) as *const _", derefs)
                        } else {
                            format!("{}{}...", autoref, derefs)
                        };
                        lint.span_help(
                            sp,
                            &format!("disambiguate the method call with `({})`", self_adjusted,),
                        );
                    }

                    lint.emit();
                },
            );
        } else {
            // trait implementations require full disambiguation to not clash with the new prelude
            // additions (i.e. convert from dot-call to fully-qualified call)
            self.tcx.struct_span_lint_hir(
                prelude_or_array_lint,
                call_expr.hir_id,
                call_expr.span,
                |lint| {
                    let sp = call_expr.span;
                    let trait_name = self.trait_path_or_bare_name(
                        span,
                        call_expr.hir_id,
                        pick.item.container.id(),
                    );

                    let mut lint = lint.build(&format!(
                        "trait method `{}` will become ambiguous in Rust 2021",
                        segment.ident.name
                    ));

                    let (self_adjusted, precise) = self.adjust_expr(pick, self_expr, sp);
                    if precise {
                        let args = args
                            .iter()
                            .skip(1)
                            .map(|arg| {
                                let span = arg.span.find_ancestor_inside(sp).unwrap_or_default();
                                format!(
                                    ", {}",
                                    self.sess().source_map().span_to_snippet(span).unwrap()
                                )
                            })
                            .collect::<String>();

                        lint.span_suggestion(
                            sp,
                            "disambiguate the associated function",
                            format!(
                                "{}::{}({}{})",
                                trait_name, segment.ident.name, self_adjusted, args
                            ),
                            Applicability::MachineApplicable,
                        );
                    } else {
                        lint.span_help(
                            sp,
                            &format!(
                                "disambiguate the associated function with `{}::{}(...)`",
                                trait_name, segment.ident,
                            ),
                        );
                    }

                    lint.emit();
                },
            );
        }
    }

    pub(super) fn lint_fully_qualified_call_from_2018(
        &self,
        span: Span,
        method_name: Ident,
        self_ty: Ty<'tcx>,
        self_ty_span: Span,
        expr_id: hir::HirId,
        pick: &Pick<'tcx>,
    ) {
        // Rust 2021 and later is already using the new prelude
        if span.rust_2021() {
            return;
        }

        // These are the fully qualified methods added to prelude in Rust 2021
        if !matches!(method_name.name, sym::try_into | sym::try_from | sym::from_iter) {
            return;
        }

        // No need to lint if method came from std/core, as that will now be in the prelude
        if matches!(self.tcx.crate_name(pick.item.def_id.krate), sym::std | sym::core) {
            return;
        }

        // For from_iter, check if the type actually implements FromIterator.
        // If we know it does not, we don't need to warn.
        if method_name.name == sym::from_iter {
            if let Some(trait_def_id) = self.tcx.get_diagnostic_item(sym::FromIterator) {
                if !self
                    .infcx
                    .type_implements_trait(
                        trait_def_id,
                        self_ty,
                        InternalSubsts::empty(),
                        self.param_env,
                    )
                    .may_apply()
                {
                    return;
                }
            }
        }

        // No need to lint if this is an inherent method called on a specific type, like `Vec::foo(...)`,
        // since such methods take precedence over trait methods.
        if matches!(pick.kind, probe::PickKind::InherentImplPick) {
            return;
        }

        self.tcx.struct_span_lint_hir(RUST_2021_PRELUDE_COLLISIONS, expr_id, span, |lint| {
            // "type" refers to either a type or, more likely, a trait from which
            // the associated function or method is from.
            let trait_path = self.trait_path_or_bare_name(span, expr_id, pick.item.container.id());
            let trait_generics = self.tcx.generics_of(pick.item.container.id());

            let trait_name =
                if trait_generics.params.len() <= trait_generics.has_self as usize {
                    trait_path
                } else {
                    let counts = trait_generics.own_counts();
                    format!(
                        "{}<{}>",
                        trait_path,
                        std::iter::repeat("'_")
                            .take(counts.lifetimes)
                            .chain(std::iter::repeat("_").take(
                                counts.types + counts.consts - trait_generics.has_self as usize
                            ))
                            .collect::<Vec<_>>()
                            .join(", ")
                    )
                };

            let mut lint = lint.build(&format!(
                "trait-associated function `{}` will become ambiguous in Rust 2021",
                method_name.name
            ));

            let mut self_ty_name = self
                .sess()
                .source_map()
                .span_to_snippet(self_ty_span.find_ancestor_inside(span).unwrap_or_default())
                .unwrap_or_else(|_| self_ty.to_string());

            // Get the number of generics the self type has (if an Adt) unless we can determine that
            // the user has written the self type with generics already which we (naively) do by looking
            // for a "<" in `self_ty_name`.
            if !self_ty_name.contains('<') {
                if let Adt(def, _) = self_ty.kind() {
                    let generics = self.tcx.generics_of(def.did);
                    if !generics.params.is_empty() {
                        let counts = generics.own_counts();
                        self_ty_name += &format!(
                            "<{}>",
                            std::iter::repeat("'_")
                                .take(counts.lifetimes)
                                .chain(std::iter::repeat("_").take(counts.types + counts.consts))
                                .collect::<Vec<_>>()
                                .join(", ")
                        );
                    }
                }
            }
            lint.span_suggestion(
                span,
                "disambiguate the associated function",
                format!("<{} as {}>::{}", self_ty_name, trait_name, method_name.name,),
                Applicability::MachineApplicable,
            );

            lint.emit();
        });
    }

    fn trait_path_or_bare_name(
        &self,
        span: Span,
        expr_hir_id: HirId,
        trait_def_id: DefId,
    ) -> String {
        self.trait_path(span, expr_hir_id, trait_def_id).unwrap_or_else(|| {
            let key = self.tcx.def_key(trait_def_id);
            format!("{}", key.disambiguated_data.data)
        })
    }

    fn trait_path(&self, span: Span, expr_hir_id: HirId, trait_def_id: DefId) -> Option<String> {
        let applicable_traits = self.tcx.in_scope_traits(expr_hir_id)?;
        let applicable_trait = applicable_traits.iter().find(|t| t.def_id == trait_def_id)?;
        if applicable_trait.import_ids.is_empty() {
            // The trait was declared within the module, we only need to use its name.
            return None;
        }

        let import_items: Vec<_> = applicable_trait
            .import_ids
            .iter()
            .map(|&import_id| {
                let hir_id = self.tcx.hir().local_def_id_to_hir_id(import_id);
                self.tcx.hir().expect_item(hir_id)
            })
            .collect();

        // Find an identifier with which this trait was imported (note that `_` doesn't count).
        let any_id = import_items
            .iter()
            .filter_map(|item| if item.ident.name != Underscore { Some(item.ident) } else { None })
            .next();
        if let Some(any_id) = any_id {
            if any_id.name == Empty {
                // Glob import, so just use its name.
                return None;
            } else {
                return Some(format!("{}", any_id));
            }
        }

        // All that is left is `_`! We need to use the full path. It doesn't matter which one we pick,
        // so just take the first one.
        match import_items[0].kind {
            ItemKind::Use(path, _) => Some(
                path.segments
                    .iter()
                    .map(|segment| segment.ident.to_string())
                    .collect::<Vec<_>>()
                    .join("::"),
            ),
            _ => {
                span_bug!(span, "unexpected item kind, expected a use: {:?}", import_items[0].kind);
            }
        }
    }

    /// Creates a string version of the `expr` that includes explicit adjustments.
    /// Returns the string and also a bool indicating whther this is a *precise*
    /// suggestion.
    fn adjust_expr(
        &self,
        pick: &Pick<'tcx>,
        expr: &hir::Expr<'tcx>,
        outer: Span,
    ) -> (String, bool) {
        let derefs = "*".repeat(pick.autoderefs);

        let autoref = match pick.autoref_or_ptr_adjustment {
            Some(probe::AutorefOrPtrAdjustment::Autoref { mutbl: Mutability::Mut, .. }) => "&mut ",
            Some(probe::AutorefOrPtrAdjustment::Autoref { mutbl: Mutability::Not, .. }) => "&",
            Some(probe::AutorefOrPtrAdjustment::ToConstPtr) | None => "",
        };

        let (expr_text, precise) = if let Ok(expr_text) = self
            .sess()
            .source_map()
            .span_to_snippet(expr.span.find_ancestor_inside(outer).unwrap_or_default())
        {
            (expr_text, true)
        } else {
            ("(..)".to_string(), false)
        };

        let adjusted_text = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) =
            pick.autoref_or_ptr_adjustment
        {
            format!("{}{} as *const _", derefs, expr_text)
        } else {
            format!("{}{}{}", autoref, derefs, expr_text)
        };

        (adjusted_text, precise)
    }
}
<|endoftext|>


<commit_before>#[cfg(test)]
mod get_repos_should {
    use super::*;

    #[test]
    fn return_repos_with_app_name_hello_world_library_and_language_rust_and_program_type_lib_and_user_intrepion(
    ) {
        let expected = vec![GitHubRepository {
            app_name: "hello-world-library".to_string(),
            language: ProgrammingLanguage::Rust,
            program_type: ProgramType::Library,
            server: None,
            user: "intrepion".to_string(),
        }];
    }
}

enum ProgrammingLanguage {
    Rust,
}

enum ProgramType {
    Library,
}

struct GitHubRepository {
    app_name: String,
    language: ProgrammingLanguage,
    program_type: ProgramType,
    user: String,
}
<commit_msg>green<commit_after>#[cfg(test)]
mod get_repos_should {
    use super::*;

    #[test]
    fn return_repos_with_app_name_hello_world_library_and_language_rust_and_program_type_lib_and_user_intrepion(
    ) {
        let expected = vec![GitHubRepository {
            app_name: "hello-world-library".to_string(),
            language: ProgrammingLanguage::Rust,
            program_type: ProgramType::Library,
            server_type: None,
            user: "intrepion".to_string(),
        }];
    }
}

enum ProgrammingLanguage {
    Rust,
}

enum ProgramType {
    Library,
}

struct GitHubRepository {
    app_name: String,
    language: ProgrammingLanguage,
    program_type: ProgramType,
    server_type: Option<String>,
    user: String,
}
<|endoftext|>


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

use self::TypeSym::*;

use crate::sym::TermSym::{
    SymClassConstructorAndModule, SymConst, SymFct, SymGlobal, SymModule,
    SymStructConstructorAndModule, SymVar,
};
use crate::ty::TypeListId;
use crate::vm::module::ModuleId;
use crate::vm::{
    ClassId, ConstId, EnumId, FctId, FieldId, GlobalId, NamespaceId, StructId, TraitId, VarId,
};
use dora_parser::interner::Name;

#[derive(Debug)]
pub struct SymTable {
    levels: Vec<SymLevel>,
}

impl SymTable {
    pub fn new() -> SymTable {
        SymTable {
            levels: vec![SymLevel::new()],
        }
    }

    pub fn push_level(&mut self) {
        self.levels.push(SymLevel::new());
    }

    pub fn pop_level(&mut self) {
        assert!(self.levels.len() > 1);

        self.levels.pop();
    }

    pub fn levels(&self) -> usize {
        self.levels.len()
    }

    pub fn get_type(&self, name: Name) -> Option<TypeSym> {
        for level in self.levels.iter().rev() {
            if let Some(val) = level.get_type(name) {
                return Some(val.clone());
            }
        }

        None
    }

    pub fn get_term(&self, name: Name) -> Option<TermSym> {
        for level in self.levels.iter().rev() {
            if let Some(val) = level.get_term(name) {
                return Some(val.clone());
            }
        }

        None
    }

    pub fn get_class(&self, name: Name) -> Option<ClassId> {
        self.get_type(name).and_then(|n| n.to_class())
    }

    pub fn get_const(&self, name: Name) -> Option<ConstId> {
        self.get_term(name).and_then(|n| n.to_const())
    }

    pub fn get_fct(&self, name: Name) -> Option<FctId> {
        self.get_term(name).and_then(|n| n.to_fct())
    }

    pub fn get_struct(&self, name: Name) -> Option<StructId> {
        self.get_type(name).and_then(|n| n.to_struct())
    }

    pub fn get_trait(&self, name: Name) -> Option<TraitId> {
        self.get_type(name).and_then(|n| n.to_trait())
    }

    pub fn get_module(&self, name: Name) -> Option<ModuleId> {
        self.get_term(name).and_then(|n| n.to_module())
    }

    pub fn get_enum(&self, name: Name) -> Option<EnumId> {
        self.get_type(name).and_then(|n| n.to_enum())
    }

    pub fn get_global(&self, name: Name) -> Option<GlobalId> {
        self.get_term(name).and_then(|n| n.to_global())
    }

    pub fn get_var(&self, name: Name) -> Option<VarId> {
        self.get_term(name).and_then(|n| n.to_var())
    }

    pub fn insert_type(&mut self, name: Name, sym: TypeSym) -> Option<TypeSym> {
        self.levels.last_mut().unwrap().insert_type(name, sym)
    }

    pub fn insert_term(&mut self, name: Name, sym: TermSym) -> Option<TermSym> {
        self.levels.last_mut().unwrap().insert_term(name, sym)
    }
}

#[derive(Debug)]
pub struct SymLevel {
    types: HashMap<Name, TypeSym>,
    terms: HashMap<Name, TermSym>,
}

impl SymLevel {
    // creates a new table
    pub fn new() -> SymLevel {
        SymLevel {
            types: HashMap::new(),
            terms: HashMap::new(),
        }
    }

    pub fn contains_type(&self, name: Name) -> bool {
        self.types.contains_key(&name)
    }

    pub fn get_type(&self, name: Name) -> Option<&TypeSym> {
        self.types.get(&name)
    }

    pub fn insert_type(&mut self, name: Name, sym: TypeSym) -> Option<TypeSym> {
        self.types.insert(name, sym)
    }

    pub fn contains_term(&self, name: Name) -> bool {
        self.terms.contains_key(&name)
    }

    pub fn get_term(&self, name: Name) -> Option<&TermSym> {
        self.terms.get(&name)
    }

    pub fn insert_term(&mut self, name: Name, sym: TermSym) -> Option<TermSym> {
        self.terms.insert(name, sym)
    }
}

#[derive(Debug, Clone)]
pub enum TypeSym {
    SymClass(ClassId),
    SymStruct(StructId),
    SymTrait(TraitId),
    SymTypeParam(TypeListId),
    SymEnum(EnumId),
}

#[derive(Debug, Clone)]
pub enum TermSym {
    SymField(FieldId),
    SymFct(FctId),
    SymVar(VarId),
    SymModule(ModuleId),
    SymClassConstructorAndModule(ClassId, ModuleId),
    SymStructConstructorAndModule(StructId, ModuleId),
    SymGlobal(GlobalId),
    SymConst(ConstId),
    SymClassConstructor(ClassId),
    SymStructConstructor(StructId),
    SymNamespace(NamespaceId),
}

impl TypeSym {
    pub fn is_class(&self) -> bool {
        match *self {
            SymClass(_) => true,
            _ => false,
        }
    }

    pub fn to_class(&self) -> Option<ClassId> {
        match *self {
            SymClass(id) => Some(id),
            _ => None,
        }
    }

    pub fn is_struct(&self) -> bool {
        match *self {
            SymStruct(_) => true,
            _ => false,
        }
    }

    pub fn to_struct(&self) -> Option<StructId> {
        match *self {
            SymStruct(id) => Some(id),
            _ => None,
        }
    }

    pub fn is_trait(&self) -> bool {
        match *self {
            SymTrait(_) => true,
            _ => false,
        }
    }

    pub fn to_trait(&self) -> Option<TraitId> {
        match *self {
            SymTrait(id) => Some(id),
            _ => None,
        }
    }

    pub fn is_type_param(&self) -> bool {
        match *self {
            SymTypeParam(_) => true,
            _ => false,
        }
    }

    pub fn is_enum(&self) -> bool {
        match *self {
            SymEnum(_) => true,
            _ => false,
        }
    }

    pub fn to_enum(&self) -> Option<EnumId> {
        match *self {
            SymEnum(id) => Some(id),
            _ => None,
        }
    }
}

impl TermSym {
    pub fn is_fct(&self) -> bool {
        match *self {
            SymFct(_) => true,
            _ => false,
        }
    }

    pub fn to_fct(&self) -> Option<FctId> {
        match *self {
            SymFct(id) => Some(id),
            _ => None,
        }
    }

    pub fn is_var(&self) -> bool {
        match *self {
            SymVar(_) => true,
            _ => false,
        }
    }

    pub fn to_var(&self) -> Option<VarId> {
        match *self {
            SymVar(id) => Some(id),
            _ => None,
        }
    }

    pub fn is_const(&self) -> bool {
        match *self {
            SymConst(_) => true,
            _ => false,
        }
    }

    pub fn to_const(&self) -> Option<ConstId> {
        match *self {
            SymConst(id) => Some(id),
            _ => None,
        }
    }

    pub fn is_global(&self) -> bool {
        match *self {
            SymGlobal(_) => true,
            _ => false,
        }
    }

    pub fn to_global(&self) -> Option<GlobalId> {
        match *self {
            SymGlobal(id) => Some(id),
            _ => None,
        }
    }

    pub fn is_module(&self) -> bool {
        match *self {
            SymModule(_) => true,
            _ => false,
        }
    }

    pub fn to_module(&self) -> Option<ModuleId> {
        match *self {
            SymModule(id) => Some(id),
            SymClassConstructorAndModule(_, id) => Some(id),
            SymStructConstructorAndModule(_, id) => Some(id),
            _ => None,
        }
    }
}
<commit_msg>add SymTables struct<commit_after>use std::collections::HashMap;

use self::TypeSym::*;

use crate::sym::TermSym::{
    SymClassConstructorAndModule, SymConst, SymFct, SymGlobal, SymModule,
    SymStructConstructorAndModule, SymVar,
};
use crate::ty::TypeListId;
use crate::vm::module::ModuleId;
use crate::vm::{
    ClassId, ConstId, EnumId, FctId, FieldId, GlobalId, NamespaceId, StructId, TraitId, VarId,
};
use dora_parser::interner::Name;

#[derive(Debug)]
pub struct SymTable {
    levels: Vec<SymLevel>,
}

impl SymTable {
    pub fn new() -> SymTable {
        SymTable {
            levels: vec![SymLevel::new()],
        }
    }

    pub fn push_level(&mut self) {
        self.levels.push(SymLevel::new());
    }

    pub fn pop_level(&mut self) {
        assert!(self.levels.len() > 1);

        self.levels.pop();
    }

    pub fn levels(&self) -> usize {
        self.levels.len()
    }

    pub fn get_type(&self, name: Name) -> Option<TypeSym> {
        for level in self.levels.iter().rev() {
            if let Some(val) = level.get_type(name) {
                return Some(val.clone());
            }
        }

        None
    }

    pub fn get_term(&self, name: Name) -> Option<TermSym> {
        for level in self.levels.iter().rev() {
            if let Some(val) = level.get_term(name) {
                return Some(val.clone());
            }
        }

        None
    }

    pub fn get_class(&self, name: Name) -> Option<ClassId> {
        self.get_type(name).and_then(|n| n.to_class())
    }

    pub fn get_const(&self, name: Name) -> Option<ConstId> {
        self.get_term(name).and_then(|n| n.to_const())
    }

    pub fn get_fct(&self, name: Name) -> Option<FctId> {
        self.get_term(name).and_then(|n| n.to_fct())
    }

    pub fn get_struct(&self, name: Name) -> Option<StructId> {
        self.get_type(name).and_then(|n| n.to_struct())
    }

    pub fn get_trait(&self, name: Name) -> Option<TraitId> {
        self.get_type(name).and_then(|n| n.to_trait())
    }

    pub fn get_module(&self, name: Name) -> Option<ModuleId> {
        self.get_term(name).and_then(|n| n.to_module())
    }

    pub fn get_enum(&self, name: Name) -> Option<EnumId> {
        self.get_type(name).and_then(|n| n.to_enum())
    }

    pub fn get_global(&self, name: Name) -> Option<GlobalId> {
        self.get_term(name).and_then(|n| n.to_global())
    }

    pub fn get_var(&self, name: Name) -> Option<VarId> {
        self.get_term(name).and_then(|n| n.to_var())
    }

    pub fn insert_type(&mut self, name: Name, sym: TypeSym) -> Option<TypeSym> {
        self.levels.last_mut().unwrap().insert_type(name, sym)
    }

    pub fn insert_term(&mut self, name: Name, sym: TermSym) -> Option<TermSym> {
        self.levels.last_mut().unwrap().insert_term(name, sym)
    }
}

#[derive(Debug)]
pub struct SymTables<'a> {
    global: &'a SymLevel,
    levels: Vec<SymLevel>,
}

impl<'a> SymTables<'a> {
    pub fn new(global: &'a SymLevel) -> SymTables {
        SymTables {
            global,
            levels: Vec::new(),
        }
    }

    pub fn push_level(&mut self) {
        self.levels.push(SymLevel::new());
    }

    pub fn pop_level(&mut self) {
        assert!(self.levels.len() >= 1);
        self.levels.pop();
    }

    pub fn get_type(&self, name: Name) -> Option<TypeSym> {
        for level in self.levels.iter().rev() {
            if let Some(val) = level.get_type(name) {
                return Some(val.clone());
            }
        }

        self.global.get_type(name).cloned()
    }

    pub fn get_term(&self, name: Name) -> Option<TermSym> {
        for level in self.levels.iter().rev() {
            if let Some(val) = level.get_term(name) {
                return Some(val.clone());
            }
        }

        self.global.get_term(name).cloned()
    }

    pub fn get_class(&self, name: Name) -> Option<ClassId> {
        self.get_type(name).and_then(|n| n.to_class())
    }

    pub fn get_const(&self, name: Name) -> Option<ConstId> {
        self.get_term(name).and_then(|n| n.to_const())
    }

    pub fn get_fct(&self, name: Name) -> Option<FctId> {
        self.get_term(name).and_then(|n| n.to_fct())
    }

    pub fn get_struct(&self, name: Name) -> Option<StructId> {
        self.get_type(name).and_then(|n| n.to_struct())
    }

    pub fn get_trait(&self, name: Name) -> Option<TraitId> {
        self.get_type(name).and_then(|n| n.to_trait())
    }

    pub fn get_module(&self, name: Name) -> Option<ModuleId> {
        self.get_term(name).and_then(|n| n.to_module())
    }

    pub fn get_enum(&self, name: Name) -> Option<EnumId> {
        self.get_type(name).and_then(|n| n.to_enum())
    }

    pub fn get_global(&self, name: Name) -> Option<GlobalId> {
        self.get_term(name).and_then(|n| n.to_global())
    }

    pub fn get_var(&self, name: Name) -> Option<VarId> {
        self.get_term(name).and_then(|n| n.to_var())
    }

    pub fn insert_type(&mut self, name: Name, sym: TypeSym) -> Option<TypeSym> {
        self.levels.last_mut().unwrap().insert_type(name, sym)
    }

    pub fn insert_term(&mut self, name: Name, sym: TermSym) -> Option<TermSym> {
        self.levels.last_mut().unwrap().insert_term(name, sym)
    }
}

#[derive(Debug)]
pub struct SymLevel {
    types: HashMap<Name, TypeSym>,
    terms: HashMap<Name, TermSym>,
}

impl SymLevel {
    // creates a new table
    pub fn new() -> SymLevel {
        SymLevel {
            types: HashMap::new(),
            terms: HashMap::new(),
        }
    }

    pub fn contains_type(&self, name: Name) -> bool {
        self.types.contains_key(&name)
    }

    pub fn get_type(&self, name: Name) -> Option<&TypeSym> {
        self.types.get(&name)
    }

    pub fn insert_type(&mut self, name: Name, sym: TypeSym) -> Option<TypeSym> {
        self.types.insert(name, sym)
    }

    pub fn contains_term(&self, name: Name) -> bool {
        self.terms.contains_key(&name)
    }

    pub fn get_term(&self, name: Name) -> Option<&TermSym> {
        self.terms.get(&name)
    }

    pub fn insert_term(&mut self, name: Name, sym: TermSym) -> Option<TermSym> {
        self.terms.insert(name, sym)
    }
}

#[derive(Debug, Clone)]
pub enum TypeSym {
    SymClass(ClassId),
    SymStruct(StructId),
    SymTrait(TraitId),
    SymTypeParam(TypeListId),
    SymEnum(EnumId),
}

#[derive(Debug, Clone)]
pub enum TermSym {
    SymField(FieldId),
    SymFct(FctId),
    SymVar(VarId),
    SymModule(ModuleId),
    SymClassConstructorAndModule(ClassId, ModuleId),
    SymStructConstructorAndModule(StructId, ModuleId),
    SymGlobal(GlobalId),
    SymConst(ConstId),
    SymClassConstructor(ClassId),
    SymStructConstructor(StructId),
    SymNamespace(NamespaceId),
}

impl TypeSym {
    pub fn is_class(&self) -> bool {
        match *self {
            SymClass(_) => true,
            _ => false,
        }
    }

    pub fn to_class(&self) -> Option<ClassId> {
        match *self {
            SymClass(id) => Some(id),
            _ => None,
        }
    }

    pub fn is_struct(&self) -> bool {
        match *self {
            SymStruct(_) => true,
            _ => false,
        }
    }

    pub fn to_struct(&self) -> Option<StructId> {
        match *self {
            SymStruct(id) => Some(id),
            _ => None,
        }
    }

    pub fn is_trait(&self) -> bool {
        match *self {
            SymTrait(_) => true,
            _ => false,
        }
    }

    pub fn to_trait(&self) -> Option<TraitId> {
        match *self {
            SymTrait(id) => Some(id),
            _ => None,
        }
    }

    pub fn is_type_param(&self) -> bool {
        match *self {
            SymTypeParam(_) => true,
            _ => false,
        }
    }

    pub fn is_enum(&self) -> bool {
        match *self {
            SymEnum(_) => true,
            _ => false,
        }
    }

    pub fn to_enum(&self) -> Option<EnumId> {
        match *self {
            SymEnum(id) => Some(id),
            _ => None,
        }
    }
}

impl TermSym {
    pub fn is_fct(&self) -> bool {
        match *self {
            SymFct(_) => true,
            _ => false,
        }
    }

    pub fn to_fct(&self) -> Option<FctId> {
        match *self {
            SymFct(id) => Some(id),
            _ => None,
        }
    }

    pub fn is_var(&self) -> bool {
        match *self {
            SymVar(_) => true,
            _ => false,
        }
    }

    pub fn to_var(&self) -> Option<VarId> {
        match *self {
            SymVar(id) => Some(id),
            _ => None,
        }
    }

    pub fn is_const(&self) -> bool {
        match *self {
            SymConst(_) => true,
            _ => false,
        }
    }

    pub fn to_const(&self) -> Option<ConstId> {
        match *self {
            SymConst(id) => Some(id),
            _ => None,
        }
    }

    pub fn is_global(&self) -> bool {
        match *self {
            SymGlobal(_) => true,
            _ => false,
        }
    }

    pub fn to_global(&self) -> Option<GlobalId> {
        match *self {
            SymGlobal(id) => Some(id),
            _ => None,
        }
    }

    pub fn is_module(&self) -> bool {
        match *self {
            SymModule(_) => true,
            _ => false,
        }
    }

    pub fn to_module(&self) -> Option<ModuleId> {
        match *self {
            SymModule(id) => Some(id),
            SymClassConstructorAndModule(_, id) => Some(id),
            SymStructConstructorAndModule(_, id) => Some(id),
            _ => None,
        }
    }
}
<|endoftext|>


<commit_before>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::chained_bft::common;
use crate::chained_bft::{common::Author, consensus_types::vote_data::VoteData};
use crypto::hash::CryptoHash;
use failure::{Result as ProtoResult, ResultExt};
use network::proto::Vote as ProtoVote;
use proto_conv::{FromProto, IntoProto};
use serde::{Deserialize, Serialize};
use std::{
    convert::TryFrom,
    fmt::{Display, Formatter},
};
use types::{
    crypto_proxies::{Signature, ValidatorSigner, ValidatorVerifier},
    ledger_info::LedgerInfo,
};

/// VoteMsg is the struct that is ultimately sent by the voter in response for
/// receiving a proposal.
/// VoteMsg carries the `LedgerInfo` of a block that is going to be committed in case this vote
/// is gathers QuorumCertificate (see the detailed explanation in the comments of `LedgerInfo`).
#[derive(Deserialize, Serialize, Clone, Debug, PartialEq, Eq)]
pub struct VoteMsg {
    /// The data of the vote
    vote_data: VoteData,
    /// The identity of the voter.
    author: Author,
    /// LedgerInfo of a block that is going to be committed in case this vote gathers QC.
    ledger_info: LedgerInfo,
    /// Signature of the LedgerInfo
    signature: Signature,
    /// The round signatures can be aggregated into a timeout certificate if present.
    round_signature: Option<Signature>,
}

impl Display for VoteMsg {
    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
        write!(
            f,
            "Vote: [vote data: {}, author: {}, {}]",
            self.vote_data,
            self.author.short_str(),
            self.ledger_info
        )
    }
}

impl VoteMsg {
    /// Generates a new VoteMsg corresponding to the "fast-vote" path without the round signatures
    /// that can be aggregated into a timeout certificate
    pub fn new(
        vote_data: VoteData,
        author: Author,
        mut ledger_info_placeholder: LedgerInfo,
        validator_signer: &ValidatorSigner,
    ) -> Self {
        ledger_info_placeholder.set_consensus_data_hash(vote_data.hash());
        let li_sig = validator_signer
            .sign_message(ledger_info_placeholder.hash())
            .expect("Failed to sign LedgerInfo");
        Self {
            vote_data,
            author,
            ledger_info: ledger_info_placeholder,
            signature: li_sig.into(),
            round_signature: None,
        }
    }

    /// Generates a round signature, which can then be used for aggregating a timeout certificate.
    /// Typically called for generating vote messages that are sent upon timeouts.
    pub fn add_round_signature(&mut self, validator_signer: &ValidatorSigner) {
        if self.round_signature.is_some() {
            return; // round signature is already set
        }
        self.round_signature.replace(
            validator_signer
                .sign_message(common::round_hash(self.vote_data().block_round()))
                .expect("Failed to sign round")
                .into(),
        );
    }

    pub fn vote_data(&self) -> &VoteData {
        &self.vote_data
    }

    /// Return the author of the vote
    pub fn author(&self) -> Author {
        self.author
    }

    /// Return the LedgerInfo associated with this vote
    pub fn ledger_info(&self) -> &LedgerInfo {
        &self.ledger_info
    }

    /// Return the signature of the vote
    pub fn signature(&self) -> &Signature {
        &self.signature
    }

    /// Returns the signature for the vote_data.block_round() that can be aggregated for
    /// TimeoutCertificate.
    pub fn round_signature(&self) -> Option<&Signature> {
        self.round_signature.as_ref()
    }

    /// Verifies that the consensus data hash of LedgerInfo corresponds to the vote info,
    /// and then verifies the signature.
    pub fn verify(&self, validator: &ValidatorVerifier) -> failure::Result<()> {
        ensure!(
            self.ledger_info.consensus_data_hash() == self.vote_data.hash(),
            "Vote's hash mismatch with LedgerInfo"
        );
        self.signature()
            .verify(validator, self.author(), self.ledger_info.hash())
            .with_context(|e| format!("Fail to verify VoteMsg: {:?}", e))?;
        if let Some(round_signature) = &self.round_signature {
            round_signature
                .verify(
                    validator,
                    self.author(),
                    common::round_hash(self.vote_data().block_round()),
                )
                .with_context(|e| format!("Fail to verify VoteMsg: {:?}", e))?;
        }
        Ok(())
    }
}

impl IntoProto for VoteMsg {
    type ProtoType = ProtoVote;

    fn into_proto(self) -> Self::ProtoType {
        let mut proto = Self::ProtoType::new();
        proto.set_vote_data(self.vote_data.into_proto());
        proto.set_author(self.author.into());
        proto.set_ledger_info(self.ledger_info.into_proto());
        proto.set_signature(bytes::Bytes::from(self.signature.to_bytes()));
        if let Some(round_signature) = self.round_signature {
            proto.set_round_signature(bytes::Bytes::from(round_signature.to_bytes()));
        }
        proto
    }
}

impl FromProto for VoteMsg {
    type ProtoType = ProtoVote;

    fn from_proto(mut object: Self::ProtoType) -> ProtoResult<Self> {
        let vote_data = VoteData::from_proto(object.take_vote_data())?;
        let author = Author::try_from(object.take_author())?;
        let ledger_info = LedgerInfo::from_proto(object.take_ledger_info())?;
        let signature = Signature::try_from(object.get_signature())?;
        let round_signature = if object.get_round_signature().is_empty() {
            None
        } else {
            Some(Signature::try_from(object.get_round_signature())?)
        };

        Ok(VoteMsg {
            vote_data,
            author,
            ledger_info,
            signature,
            round_signature,
        })
    }
}
<commit_msg>[consensus] impl conversions from/to prost proto and VoteMsg<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::chained_bft::common;
use crate::chained_bft::{common::Author, consensus_types::vote_data::VoteData};
use crypto::hash::CryptoHash;
use failure::{Result as ProtoResult, ResultExt};
use network::proto::Vote as ProtoVote;
use proto_conv::{FromProto, IntoProto};
use serde::{Deserialize, Serialize};
use std::{
    convert::{TryFrom, TryInto},
    fmt::{Display, Formatter},
};
use types::{
    crypto_proxies::{Signature, ValidatorSigner, ValidatorVerifier},
    ledger_info::LedgerInfo,
};

/// VoteMsg is the struct that is ultimately sent by the voter in response for
/// receiving a proposal.
/// VoteMsg carries the `LedgerInfo` of a block that is going to be committed in case this vote
/// is gathers QuorumCertificate (see the detailed explanation in the comments of `LedgerInfo`).
#[derive(Deserialize, Serialize, Clone, Debug, PartialEq, Eq)]
pub struct VoteMsg {
    /// The data of the vote
    vote_data: VoteData,
    /// The identity of the voter.
    author: Author,
    /// LedgerInfo of a block that is going to be committed in case this vote gathers QC.
    ledger_info: LedgerInfo,
    /// Signature of the LedgerInfo
    signature: Signature,
    /// The round signatures can be aggregated into a timeout certificate if present.
    round_signature: Option<Signature>,
}

impl Display for VoteMsg {
    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
        write!(
            f,
            "Vote: [vote data: {}, author: {}, {}]",
            self.vote_data,
            self.author.short_str(),
            self.ledger_info
        )
    }
}

impl VoteMsg {
    /// Generates a new VoteMsg corresponding to the "fast-vote" path without the round signatures
    /// that can be aggregated into a timeout certificate
    pub fn new(
        vote_data: VoteData,
        author: Author,
        mut ledger_info_placeholder: LedgerInfo,
        validator_signer: &ValidatorSigner,
    ) -> Self {
        ledger_info_placeholder.set_consensus_data_hash(vote_data.hash());
        let li_sig = validator_signer
            .sign_message(ledger_info_placeholder.hash())
            .expect("Failed to sign LedgerInfo");
        Self {
            vote_data,
            author,
            ledger_info: ledger_info_placeholder,
            signature: li_sig.into(),
            round_signature: None,
        }
    }

    /// Generates a round signature, which can then be used for aggregating a timeout certificate.
    /// Typically called for generating vote messages that are sent upon timeouts.
    pub fn add_round_signature(&mut self, validator_signer: &ValidatorSigner) {
        if self.round_signature.is_some() {
            return; // round signature is already set
        }
        self.round_signature.replace(
            validator_signer
                .sign_message(common::round_hash(self.vote_data().block_round()))
                .expect("Failed to sign round")
                .into(),
        );
    }

    pub fn vote_data(&self) -> &VoteData {
        &self.vote_data
    }

    /// Return the author of the vote
    pub fn author(&self) -> Author {
        self.author
    }

    /// Return the LedgerInfo associated with this vote
    pub fn ledger_info(&self) -> &LedgerInfo {
        &self.ledger_info
    }

    /// Return the signature of the vote
    pub fn signature(&self) -> &Signature {
        &self.signature
    }

    /// Returns the signature for the vote_data.block_round() that can be aggregated for
    /// TimeoutCertificate.
    pub fn round_signature(&self) -> Option<&Signature> {
        self.round_signature.as_ref()
    }

    /// Verifies that the consensus data hash of LedgerInfo corresponds to the vote info,
    /// and then verifies the signature.
    pub fn verify(&self, validator: &ValidatorVerifier) -> failure::Result<()> {
        ensure!(
            self.ledger_info.consensus_data_hash() == self.vote_data.hash(),
            "Vote's hash mismatch with LedgerInfo"
        );
        self.signature()
            .verify(validator, self.author(), self.ledger_info.hash())
            .with_context(|e| format!("Fail to verify VoteMsg: {:?}", e))?;
        if let Some(round_signature) = &self.round_signature {
            round_signature
                .verify(
                    validator,
                    self.author(),
                    common::round_hash(self.vote_data().block_round()),
                )
                .with_context(|e| format!("Fail to verify VoteMsg: {:?}", e))?;
        }
        Ok(())
    }
}

impl IntoProto for VoteMsg {
    type ProtoType = ProtoVote;

    fn into_proto(self) -> Self::ProtoType {
        let mut proto = Self::ProtoType::new();
        proto.set_vote_data(self.vote_data.into_proto());
        proto.set_author(self.author.into());
        proto.set_ledger_info(self.ledger_info.into_proto());
        proto.set_signature(bytes::Bytes::from(self.signature.to_bytes()));
        if let Some(round_signature) = self.round_signature {
            proto.set_round_signature(bytes::Bytes::from(round_signature.to_bytes()));
        }
        proto
    }
}

impl FromProto for VoteMsg {
    type ProtoType = ProtoVote;

    fn from_proto(mut object: Self::ProtoType) -> ProtoResult<Self> {
        let vote_data = VoteData::from_proto(object.take_vote_data())?;
        let author = Author::try_from(object.take_author())?;
        let ledger_info = LedgerInfo::from_proto(object.take_ledger_info())?;
        let signature = Signature::try_from(object.get_signature())?;
        let round_signature = if object.get_round_signature().is_empty() {
            None
        } else {
            Some(Signature::try_from(object.get_round_signature())?)
        };

        Ok(VoteMsg {
            vote_data,
            author,
            ledger_info,
            signature,
            round_signature,
        })
    }
}

impl TryFrom<network::proto::consensus_prost::Vote> for VoteMsg {
    type Error = failure::Error;

    fn try_from(proto: network::proto::consensus_prost::Vote) -> failure::Result<Self> {
        let vote_data = proto
            .vote_data
            .ok_or_else(|| format_err!("Missing vote_data"))?
            .try_into()?;
        let author = Author::try_from(proto.author)?;
        let ledger_info = proto
            .ledger_info
            .ok_or_else(|| format_err!("Missing ledger_info"))?
            .try_into()?;
        let signature = Signature::try_from(&proto.signature)?;
        let round_signature = if proto.round_signature.is_empty() {
            None
        } else {
            Some(Signature::try_from(&proto.round_signature)?)
        };
        Ok(Self {
            vote_data,
            author,
            ledger_info,
            signature,
            round_signature,
        })
    }
}

impl From<VoteMsg> for network::proto::consensus_prost::Vote {
    fn from(vote: VoteMsg) -> Self {
        Self {
            vote_data: Some(vote.vote_data.into()),
            author: vote.author.into(),
            ledger_info: Some(vote.ledger_info.into()),
            signature: vote.signature.to_bytes(),
            round_signature: vote
                .round_signature
                .map(|sig| sig.to_bytes())
                .unwrap_or_else(Vec::new),
        }
    }
}
<|endoftext|>


<commit_before>use std::cell::RefCell;
use std::ops::DerefMut;

use game::*;
use game::data::*;
use ecs::*;
use util::{LeakyReserver, Schedule};
use coord::Coord;

pub struct EntityIdReserver(RefCell<LeakyReserver<EntityId>>);

impl EntityIdReserver {
    pub fn new() -> Self {
        EntityIdReserver(RefCell::new(LeakyReserver::new()))
    }

    pub fn new_id(&self) -> EntityId {
        self.0.borrow_mut().reserve()
    }
}

enum MainMenuSelection {
    NewGame,
    Quit,
    Continue(GameState),
}

pub struct GameCtx<Renderer: KnowledgeRenderer, Input: InputSource> {
    renderer: RefCell<Renderer>,
    input_source: Input,
    entity_ids: EntityIdReserver,
    turn_id: u64,
    action_id: u64,
    pc_observer: Shadowcast,
    behaviour_ctx: BehaviourCtx<Renderer>,
    rule_reactions: Vec<Reaction>,
    ecs_action: EcsAction,
    action_schedule: Schedule<ActionArgs>,
    width: usize,
    height: usize,
    rng: GameRng,
    language: Box<Language>,
}

#[derive(Clone, Copy)]
pub struct GlobalIds {
    pc_id: EntityId,
    level_id: LevelId,
}

struct GameState {
    levels: LevelTable,
    ids: Option<GlobalIds>,
}

impl GameState {
    pub fn new() -> Self {
        GameState {
            levels: LevelTable::new(),
            ids: None,
        }
    }
}

impl<Renderer: KnowledgeRenderer, Input: 'static + InputSource + Clone> GameCtx<Renderer, Input> {
    pub fn new(renderer: Renderer, input_source: Input, seed: usize, width: usize, height: usize) -> Self {
        let entity_ids = EntityIdReserver::new();
        GameCtx {
            renderer: RefCell::new(renderer),
            input_source: input_source.clone(),
            entity_ids: entity_ids,
            turn_id: 0,
            action_id: 0,
            pc_observer: Shadowcast::new(),
            behaviour_ctx: BehaviourCtx::new(input_source),
            rule_reactions: Vec::new(),
            ecs_action: EcsAction::new(),
            action_schedule: Schedule::new(),
            width: width,
            height: height,
            rng: GameRng::new(seed),
            language: Box::new(languages::English),
        }
    }

    pub fn run(&mut self, _args: Arguments) -> Result<()> {

        let mut current_game_state = None;

        loop {

            let control_map = ControlMap::default(); // TODO load this from a file

            let mut menu = Menu::new();

            if let Some(game_state) = current_game_state.take() {
                menu.push(MenuItem::new(MenuMessageType::Continue, MainMenuSelection::Continue(game_state)));
            }

            menu.push(MenuItem::new(MenuMessageType::NewGame, MainMenuSelection::NewGame));
            menu.push(MenuItem::new(MenuMessageType::Quit, MainMenuSelection::Quit));

            let item = menu_operation::run(
                self.renderer.borrow_mut().deref_mut(),
                &mut self.input_source,
                Some(MessageType::Title),
                &self.language,
                menu);

            let mut game_state = match item {
                MainMenuSelection::Quit => {
                    return Ok(());
                }
                MainMenuSelection::NewGame => {
                    let mut game_state = GameState::new();

                    self.init_demo(&mut game_state);
                    self.intro_message(&control_map);
                    self.welcome_message(&game_state);

                    game_state
                }
                MainMenuSelection::Continue(game_state) => game_state,
            };

            Self::install_control_map(&mut game_state, control_map);

            self.game_loop(&mut game_state)?;

            current_game_state = Some(game_state);
        }
    }

    fn install_control_map(game_state: &mut GameState, control_map: ControlMap) {
        let GlobalIds { pc_id, level_id } = game_state.ids.expect("Uninitialised game state");

        let level = game_state.levels.level_mut(level_id);
        level.ecs.insert_control_map(pc_id, control_map);
    }

    fn game_loop(&mut self, game_state: &mut GameState) -> Result<()> {
        loop {

            let GlobalIds { pc_id, level_id } = game_state.ids.expect("Uninitialised game state");

            self.turn_id += 1;

            let resolution = {
                let level = game_state.levels.level_mut(level_id);
                if let Some(turn_event) = level.turn_schedule.next() {

                    TurnEnv {
                        turn_id: self.turn_id,
                        action_id: &mut self.action_id,
                        level_id: level_id,
                        entity_id: turn_event.event,
                        pc_id: pc_id,
                        renderer: &self.renderer,
                        ecs: &mut level.ecs,
                        spatial_hash: &mut level.spatial_hash,
                        behaviour_ctx: &self.behaviour_ctx,
                        rule_reactions: &mut self.rule_reactions,
                        ecs_action: &mut self.ecs_action,
                        action_schedule: &mut self.action_schedule,
                        turn_schedule: &mut level.turn_schedule,
                        pc_observer: &self.pc_observer,
                        entity_ids: &self.entity_ids,
                        rng: &self.rng,
                        language: &self.language,
                    }.turn()?

                } else {
                    return Err(Error::ScheduleEmpty);
                }
            };

            match resolution {
                TurnResolution::Quit(entity_id) => {
                    let level = game_state.levels.level_mut(level_id);
                    let ticket = level.turn_schedule.insert(entity_id, 0);
                    level.ecs.insert_schedule_ticket(entity_id, ticket);
                    return Ok(());
                }
                TurnResolution::Schedule(entity_id, delay) => {
                    let level = game_state.levels.level_mut(level_id);
                    let ticket = level.turn_schedule.insert(entity_id, delay);
                    level.ecs.insert_schedule_ticket(entity_id, ticket);
                }
                TurnResolution::LevelSwitch(level_switch) => {
                    self.switch_level(level_switch, game_state);
                }
            }
        }
    }

    fn welcome_message(&self, game_state: &GameState) {
        let GlobalIds { pc_id, level_id } = game_state.ids.expect("Unitialised game state");

        let ref ecs = game_state.levels.level(level_id).ecs;
        ecs.message_log_borrow_mut(pc_id).unwrap().add(MessageType::Welcome);
    }

    fn intro_message(&mut self, control_map: &ControlMap) {

        let mut message = Message::new();

        self.language.translate(MessageType::Intro, &mut message);
        message.push(MessagePart::Newline);
        message.push(MessagePart::Newline);
        self.language.translate(MessageType::PressAnyKey, &mut message);
        message.push(MessagePart::Newline);
        message.push(MessagePart::Newline);
        message.push(MessagePart::Newline);
        self.language.translate_controls(control_map, &mut message);

        display_message_scrolling(self.renderer.borrow_mut().deref_mut(), &mut self.input_source, &message, true);
    }

    fn init_demo(&mut self, game_state: &mut GameState) {

        let pc_id = self.entity_ids.new_id();

        let mut action = EcsAction::new();
        prototypes::pc(action.entity_mut(pc_id), Coord::new(0, 0));

        let level = Level::new_with_pc(TerrainType::DemoA,
                                       pc_id,
                                       &mut action,
                                       &self.entity_ids,
                                       &self.rng,
                                       self.action_id);

        self.action_id += 1;

        let level_id = game_state.levels.add_level(level);

        game_state.ids = Some(GlobalIds {
            pc_id: pc_id,
            level_id: level_id,
        });
    }

    fn switch_level(&mut self, level_switch: LevelSwitch, game_state: &mut GameState) {
        let GlobalIds { pc_id, ref mut level_id } = game_state.ids.expect("Unitialised game state");

        let mut pc_insert = EcsAction::new();
        let mut pc_remove = EcsAction::new();

        {
            let current_level = game_state.levels.level_mut(*level_id);
            pc_remove.remove_entity_by_id(pc_id, &current_level.ecs);
            current_level.commit_into(&mut pc_remove, &mut pc_insert, self.action_id);
        }

        self.action_id += 1;

        let new_level = Level::new_with_pc(level_switch.terrain_type,
                                           pc_id,
                                           &mut pc_insert,
                                           &self.entity_ids,
                                           &self.rng,
                                           self.action_id);
        self.action_id += 1;

         *level_id = game_state.levels.add_level(new_level);
    }
}
<commit_msg>Fixed level-switching bug<commit_after>use std::cell::RefCell;
use std::ops::DerefMut;

use game::*;
use game::data::*;
use ecs::*;
use util::{LeakyReserver, Schedule};
use coord::Coord;

pub struct EntityIdReserver(RefCell<LeakyReserver<EntityId>>);

impl EntityIdReserver {
    pub fn new() -> Self {
        EntityIdReserver(RefCell::new(LeakyReserver::new()))
    }

    pub fn new_id(&self) -> EntityId {
        self.0.borrow_mut().reserve()
    }
}

enum MainMenuSelection {
    NewGame,
    Quit,
    Continue(GameState),
}

pub struct GameCtx<Renderer: KnowledgeRenderer, Input: InputSource> {
    renderer: RefCell<Renderer>,
    input_source: Input,
    entity_ids: EntityIdReserver,
    turn_id: u64,
    action_id: u64,
    pc_observer: Shadowcast,
    behaviour_ctx: BehaviourCtx<Renderer>,
    rule_reactions: Vec<Reaction>,
    ecs_action: EcsAction,
    action_schedule: Schedule<ActionArgs>,
    width: usize,
    height: usize,
    rng: GameRng,
    language: Box<Language>,
}

#[derive(Clone, Copy)]
pub struct GlobalIds {
    pc_id: EntityId,
    level_id: LevelId,
}

struct GameState {
    levels: LevelTable,
    ids: Option<GlobalIds>,
}

impl GameState {
    pub fn new() -> Self {
        GameState {
            levels: LevelTable::new(),
            ids: None,
        }
    }
}

impl<Renderer: KnowledgeRenderer, Input: 'static + InputSource + Clone> GameCtx<Renderer, Input> {
    pub fn new(renderer: Renderer, input_source: Input, seed: usize, width: usize, height: usize) -> Self {
        let entity_ids = EntityIdReserver::new();
        GameCtx {
            renderer: RefCell::new(renderer),
            input_source: input_source.clone(),
            entity_ids: entity_ids,
            turn_id: 0,
            action_id: 0,
            pc_observer: Shadowcast::new(),
            behaviour_ctx: BehaviourCtx::new(input_source),
            rule_reactions: Vec::new(),
            ecs_action: EcsAction::new(),
            action_schedule: Schedule::new(),
            width: width,
            height: height,
            rng: GameRng::new(seed),
            language: Box::new(languages::English),
        }
    }

    pub fn run(&mut self, _args: Arguments) -> Result<()> {

        let mut current_game_state = None;

        loop {

            let control_map = ControlMap::default(); // TODO load this from a file

            let mut menu = Menu::new();

            if let Some(game_state) = current_game_state.take() {
                menu.push(MenuItem::new(MenuMessageType::Continue, MainMenuSelection::Continue(game_state)));
            }

            menu.push(MenuItem::new(MenuMessageType::NewGame, MainMenuSelection::NewGame));
            menu.push(MenuItem::new(MenuMessageType::Quit, MainMenuSelection::Quit));

            let item = menu_operation::run(
                self.renderer.borrow_mut().deref_mut(),
                &mut self.input_source,
                Some(MessageType::Title),
                &self.language,
                menu);

            let mut game_state = match item {
                MainMenuSelection::Quit => {
                    return Ok(());
                }
                MainMenuSelection::NewGame => {
                    let mut game_state = GameState::new();

                    self.init_demo(&mut game_state);
                    self.intro_message(&control_map);
                    self.welcome_message(&game_state);

                    game_state
                }
                MainMenuSelection::Continue(game_state) => game_state,
            };

            Self::install_control_map(&mut game_state, control_map);

            self.game_loop(&mut game_state)?;

            current_game_state = Some(game_state);
        }
    }

    fn install_control_map(game_state: &mut GameState, control_map: ControlMap) {
        let GlobalIds { pc_id, level_id } = game_state.ids.expect("Uninitialised game state");

        let level = game_state.levels.level_mut(level_id);
        level.ecs.insert_control_map(pc_id, control_map);
    }

    fn game_loop(&mut self, game_state: &mut GameState) -> Result<()> {
        loop {

            let GlobalIds { pc_id, level_id } = game_state.ids.expect("Uninitialised game state");

            self.turn_id += 1;

            let resolution = {
                let level = game_state.levels.level_mut(level_id);
                if let Some(turn_event) = level.turn_schedule.next() {

                    TurnEnv {
                        turn_id: self.turn_id,
                        action_id: &mut self.action_id,
                        level_id: level_id,
                        entity_id: turn_event.event,
                        pc_id: pc_id,
                        renderer: &self.renderer,
                        ecs: &mut level.ecs,
                        spatial_hash: &mut level.spatial_hash,
                        behaviour_ctx: &self.behaviour_ctx,
                        rule_reactions: &mut self.rule_reactions,
                        ecs_action: &mut self.ecs_action,
                        action_schedule: &mut self.action_schedule,
                        turn_schedule: &mut level.turn_schedule,
                        pc_observer: &self.pc_observer,
                        entity_ids: &self.entity_ids,
                        rng: &self.rng,
                        language: &self.language,
                    }.turn()?

                } else {
                    return Err(Error::ScheduleEmpty);
                }
            };

            match resolution {
                TurnResolution::Quit(entity_id) => {
                    let level = game_state.levels.level_mut(level_id);
                    let ticket = level.turn_schedule.insert(entity_id, 0);
                    level.ecs.insert_schedule_ticket(entity_id, ticket);
                    return Ok(());
                }
                TurnResolution::Schedule(entity_id, delay) => {
                    let level = game_state.levels.level_mut(level_id);
                    let ticket = level.turn_schedule.insert(entity_id, delay);
                    level.ecs.insert_schedule_ticket(entity_id, ticket);
                }
                TurnResolution::LevelSwitch(level_switch) => {
                    self.switch_level(level_switch, game_state);
                }
            }
        }
    }

    fn welcome_message(&self, game_state: &GameState) {
        let GlobalIds { pc_id, level_id } = game_state.ids.expect("Unitialised game state");

        let ref ecs = game_state.levels.level(level_id).ecs;
        ecs.message_log_borrow_mut(pc_id).unwrap().add(MessageType::Welcome);
    }

    fn intro_message(&mut self, control_map: &ControlMap) {

        let mut message = Message::new();

        self.language.translate(MessageType::Intro, &mut message);
        message.push(MessagePart::Newline);
        message.push(MessagePart::Newline);
        self.language.translate(MessageType::PressAnyKey, &mut message);
        message.push(MessagePart::Newline);
        message.push(MessagePart::Newline);
        message.push(MessagePart::Newline);
        self.language.translate_controls(control_map, &mut message);

        display_message_scrolling(self.renderer.borrow_mut().deref_mut(), &mut self.input_source, &message, true);
    }

    fn init_demo(&mut self, game_state: &mut GameState) {

        let pc_id = self.entity_ids.new_id();

        let mut action = EcsAction::new();
        prototypes::pc(action.entity_mut(pc_id), Coord::new(0, 0));

        let level = Level::new_with_pc(TerrainType::DemoA,
                                       pc_id,
                                       &mut action,
                                       &self.entity_ids,
                                       &self.rng,
                                       self.action_id);

        self.action_id += 1;

        let level_id = game_state.levels.add_level(level);

        game_state.ids = Some(GlobalIds {
            pc_id: pc_id,
            level_id: level_id,
        });
    }

    fn switch_level(&mut self, level_switch: LevelSwitch, game_state: &mut GameState) {
        let ids = game_state.ids.as_mut().expect("Unitialised game state");

        let mut pc_insert = EcsAction::new();
        let mut pc_remove = EcsAction::new();

        {
            let current_level = game_state.levels.level_mut(ids.level_id);
            pc_remove.remove_entity_by_id(ids.pc_id, &current_level.ecs);
            current_level.commit_into(&mut pc_remove, &mut pc_insert, self.action_id);
        }

        self.action_id += 1;

        let new_level = Level::new_with_pc(level_switch.terrain_type,
                                           ids.pc_id,
                                           &mut pc_insert,
                                           &self.entity_ids,
                                           &self.rng,
                                           self.action_id);
        self.action_id += 1;

        ids.level_id = game_state.levels.add_level(new_level);
    }
}
<|endoftext|>