<commit_before>use super::diagnostics::Error;
use super::item::ItemInfo;
use super::Parser;

use crate::{new_sub_parser_from_file, DirectoryOwnership};

use rustc_ast::ast::{self, Attribute, Crate, Ident, ItemKind, Mod};
use rustc_ast::attr;
use rustc_ast::token::{self, TokenKind};
use rustc_errors::PResult;
use rustc_span::source_map::{FileName, SourceMap, Span, DUMMY_SP};
use rustc_span::symbol::sym;

use std::path::{self, Path, PathBuf};

/// Information about the path to a module.
// Public for rustfmt usage.
pub struct ModulePath {
    name: String,
    path_exists: bool,
    pub result: Result<ModulePathSuccess, Error>,
}

// Public for rustfmt usage.
pub struct ModulePathSuccess {
    pub path: PathBuf,
    pub directory_ownership: DirectoryOwnership,
}

impl<'a> Parser<'a> {
    /// Parses a source module as a crate. This is the main entry point for the parser.
    pub fn parse_crate_mod(&mut self) -> PResult<'a, Crate> {
        let lo = self.token.span;
        let krate = Ok(ast::Crate {
            attrs: self.parse_inner_attributes()?,
            module: self.parse_mod_items(&token::Eof, lo)?,
            span: lo.to(self.token.span),
            // Filled in by proc_macro_harness::inject()
            proc_macros: Vec::new(),
        });
        krate
    }

    /// Parses a `mod <foo> { ... }` or `mod <foo>;` item.
    pub(super) fn parse_item_mod(&mut self, attrs: &mut Vec<Attribute>) -> PResult<'a, ItemInfo> {
        let in_cfg = crate::config::process_configure_mod(self.sess, self.cfg_mods, attrs);

        let id_span = self.token.span;
        let id = self.parse_ident()?;
        let (module, mut inner_attrs) = if self.eat(&token::Semi) {
            if in_cfg && self.recurse_into_file_modules {
                // This mod is in an external file. Let's go get it!
                let ModulePathSuccess { path, directory_ownership } =
                    self.submod_path(id, &attrs, id_span)?;
                self.eval_src_mod(path, directory_ownership, id.to_string(), id_span)?
            } else {
                (ast::Mod { inner: DUMMY_SP, items: Vec::new(), inline: false }, Vec::new())
            }
        } else {
            let old_directory = self.directory.clone();
            self.push_directory(id, &attrs);

            self.expect(&token::OpenDelim(token::Brace))?;
            let mod_inner_lo = self.token.span;
            let inner_attrs = self.parse_inner_attributes()?;
            let module = self.parse_mod_items(&token::CloseDelim(token::Brace), mod_inner_lo)?;

            self.directory = old_directory;
            (module, inner_attrs)
        };
        attrs.append(&mut inner_attrs);
        Ok((id, ItemKind::Mod(module)))
    }

    /// Given a termination token, parses all of the items in a module.
    fn parse_mod_items(&mut self, term: &TokenKind, inner_lo: Span) -> PResult<'a, Mod> {
        let mut items = vec![];
        while let Some(item) = self.parse_item()? {
            items.push(item);
            self.maybe_consume_incorrect_semicolon(&items);
        }

        if !self.eat(term) {
            let token_str = super::token_descr(&self.token);
            if !self.maybe_consume_incorrect_semicolon(&items) {
                let msg = &format!("expected item, found {}", token_str);
                let mut err = self.struct_span_err(self.token.span, msg);
                err.span_label(self.token.span, "expected item");
                return Err(err);
            }
        }

        let hi = if self.token.span.is_dummy() { inner_lo } else { self.prev_token.span };

        Ok(Mod { inner: inner_lo.to(hi), items, inline: true })
    }

    fn submod_path(
        &mut self,
        id: ast::Ident,
        outer_attrs: &[Attribute],
        id_sp: Span,
    ) -> PResult<'a, ModulePathSuccess> {
        if let Some(path) = Parser::submod_path_from_attr(outer_attrs, &self.directory.path) {
            return Ok(ModulePathSuccess {
                directory_ownership: match path.file_name().and_then(|s| s.to_str()) {
                    // All `#[path]` files are treated as though they are a `mod.rs` file.
                    // This means that `mod foo;` declarations inside `#[path]`-included
                    // files are siblings,
                    //
                    // Note that this will produce weirdness when a file named `foo.rs` is
                    // `#[path]` included and contains a `mod foo;` declaration.
                    // If you encounter this, it's your own darn fault :P
                    Some(_) => DirectoryOwnership::Owned { relative: None },
                    _ => DirectoryOwnership::UnownedViaMod,
                },
                path,
            });
        }

        let relative = match self.directory.ownership {
            DirectoryOwnership::Owned { relative } => relative,
            DirectoryOwnership::UnownedViaBlock | DirectoryOwnership::UnownedViaMod => None,
        };
        let paths =
            Parser::default_submod_path(id, relative, &self.directory.path, self.sess.source_map());

        match self.directory.ownership {
            DirectoryOwnership::Owned { .. } => {
                paths.result.map_err(|err| self.span_fatal_err(id_sp, err))
            }
            DirectoryOwnership::UnownedViaBlock => self.error_decl_mod_in_block(id_sp, paths),
            DirectoryOwnership::UnownedViaMod => self.error_cannot_declare_mod_here(id_sp, paths),
        }
    }

    fn error_decl_mod_in_block<T>(&self, id_sp: Span, paths: ModulePath) -> PResult<'a, T> {
        let msg =
            "Cannot declare a non-inline module inside a block unless it has a path attribute";
        let mut err = self.struct_span_err(id_sp, msg);
        if paths.path_exists {
            let msg = format!("Maybe `use` the module `{}` instead of redeclaring it", paths.name);
            err.span_note(id_sp, &msg);
        }
        Err(err)
    }

    fn error_cannot_declare_mod_here<T>(&self, id_sp: Span, paths: ModulePath) -> PResult<'a, T> {
        let mut err = self.struct_span_err(id_sp, "cannot declare a new module at this location");
        if !id_sp.is_dummy() {
            if let FileName::Real(src_path) = self.sess.source_map().span_to_filename(id_sp) {
                if let Some(stem) = src_path.file_stem() {
                    let mut dest_path = src_path.clone();
                    dest_path.set_file_name(stem);
                    dest_path.push("mod.rs");
                    err.span_note(
                        id_sp,
                        &format!(
                            "maybe move this module `{}` to its own \
                                    directory via `{}`",
                            src_path.display(),
                            dest_path.display()
                        ),
                    );
                }
            }
        }
        if paths.path_exists {
            err.span_note(
                id_sp,
                &format!(
                    "... or maybe `use` the module `{}` instead \
                                of possibly redeclaring it",
                    paths.name
                ),
            );
        }
        Err(err)
    }

    /// Derive a submodule path from the first found `#[path = "path_string"]`.
    /// The provided `dir_path` is joined with the `path_string`.
    // Public for rustfmt usage.
    pub fn submod_path_from_attr(attrs: &[Attribute], dir_path: &Path) -> Option<PathBuf> {
        // Extract path string from first `#[path = "path_string"]` attribute.
        let path_string = attr::first_attr_value_str_by_name(attrs, sym::path)?;
        let path_string = path_string.as_str();

        // On windows, the base path might have the form
        // `\\?\foo\bar` in which case it does not tolerate
        // mixed `/` and `\` separators, so canonicalize
        // `/` to `\`.
        #[cfg(windows)]
        let path_string = path_string.replace("/", "\\");

        Some(dir_path.join(&*path_string))
    }

    /// Returns a path to a module.
    // Public for rustfmt usage.
    pub fn default_submod_path(
        id: ast::Ident,
        relative: Option<ast::Ident>,
        dir_path: &Path,
        source_map: &SourceMap,
    ) -> ModulePath {
        // If we're in a foo.rs file instead of a mod.rs file,
        // we need to look for submodules in
        // `./foo/<id>.rs` and `./foo/<id>/mod.rs` rather than
        // `./<id>.rs` and `./<id>/mod.rs`.
        let relative_prefix_string;
        let relative_prefix = if let Some(ident) = relative {
            relative_prefix_string = format!("{}{}", ident.name, path::MAIN_SEPARATOR);
            &relative_prefix_string
        } else {
            ""
        };

        let mod_name = id.name.to_string();
        let default_path_str = format!("{}{}.rs", relative_prefix, mod_name);
        let secondary_path_str =
            format!("{}{}{}mod.rs", relative_prefix, mod_name, path::MAIN_SEPARATOR);
        let default_path = dir_path.join(&default_path_str);
        let secondary_path = dir_path.join(&secondary_path_str);
        let default_exists = source_map.file_exists(&default_path);
        let secondary_exists = source_map.file_exists(&secondary_path);

        let result = match (default_exists, secondary_exists) {
            (true, false) => Ok(ModulePathSuccess {
                path: default_path,
                directory_ownership: DirectoryOwnership::Owned { relative: Some(id) },
            }),
            (false, true) => Ok(ModulePathSuccess {
                path: secondary_path,
                directory_ownership: DirectoryOwnership::Owned { relative: None },
            }),
            (false, false) => {
                Err(Error::FileNotFoundForModule { mod_name: mod_name.clone(), default_path })
            }
            (true, true) => Err(Error::DuplicatePaths {
                mod_name: mod_name.clone(),
                default_path: default_path_str,
                secondary_path: secondary_path_str,
            }),
        };

        ModulePath { name: mod_name, path_exists: default_exists || secondary_exists, result }
    }

    /// Reads a module from a source file.
    fn eval_src_mod(
        &mut self,
        path: PathBuf,
        directory_ownership: DirectoryOwnership,
        name: String,
        id_sp: Span,
    ) -> PResult<'a, (Mod, Vec<Attribute>)> {
        let mut included_mod_stack = self.sess.included_mod_stack.borrow_mut();
        if let Some(i) = included_mod_stack.iter().position(|p| *p == path) {
            let mut err = String::from("circular modules: ");
            let len = included_mod_stack.len();
            for p in &included_mod_stack[i..len] {
                err.push_str(&p.to_string_lossy());
                err.push_str(" -> ");
            }
            err.push_str(&path.to_string_lossy());
            return Err(self.struct_span_err(id_sp, &err[..]));
        }
        included_mod_stack.push(path.clone());
        drop(included_mod_stack);

        let mut p0 =
            new_sub_parser_from_file(self.sess, &path, directory_ownership, Some(name), id_sp);
        p0.cfg_mods = self.cfg_mods;
        let mod_inner_lo = p0.token.span;
        let mod_attrs = p0.parse_inner_attributes()?;
        let mut m0 = p0.parse_mod_items(&token::Eof, mod_inner_lo)?;
        m0.inline = false;
        self.sess.included_mod_stack.borrow_mut().pop();
        Ok((m0, mod_attrs))
    }

    fn push_directory(&mut self, id: Ident, attrs: &[Attribute]) {
        if let Some(path) = attr::first_attr_value_str_by_name(attrs, sym::path) {
            self.directory.path.push(&*path.as_str());
            self.directory.ownership = DirectoryOwnership::Owned { relative: None };
        } else {
            // We have to push on the current module name in the case of relative
            // paths in order to ensure that any additional module paths from inline
            // `mod x { ... }` come after the relative extension.
            //
            // For example, a `mod z { ... }` inside `x/y.rs` should set the current
            // directory path to `/x/y/z`, not `/x/z` with a relative offset of `y`.
            if let DirectoryOwnership::Owned { relative } = &mut self.directory.ownership {
                if let Some(ident) = relative.take() {
                    // remove the relative offset
                    self.directory.path.push(&*ident.as_str());
                }
            }
            self.directory.path.push(&*id.as_str());
        }
    }
}
<commit_msg>simplify submod_path<commit_after>use super::diagnostics::Error;
use super::item::ItemInfo;
use super::Parser;

use crate::{new_sub_parser_from_file, DirectoryOwnership};

use rustc_ast::ast::{self, Attribute, Crate, Ident, ItemKind, Mod};
use rustc_ast::attr;
use rustc_ast::token::{self, TokenKind};
use rustc_errors::PResult;
use rustc_span::source_map::{FileName, SourceMap, Span, DUMMY_SP};
use rustc_span::symbol::sym;

use std::path::{self, Path, PathBuf};

/// Information about the path to a module.
// Public for rustfmt usage.
pub struct ModulePath {
    name: String,
    path_exists: bool,
    pub result: Result<ModulePathSuccess, Error>,
}

// Public for rustfmt usage.
pub struct ModulePathSuccess {
    pub path: PathBuf,
    pub directory_ownership: DirectoryOwnership,
}

impl<'a> Parser<'a> {
    /// Parses a source module as a crate. This is the main entry point for the parser.
    pub fn parse_crate_mod(&mut self) -> PResult<'a, Crate> {
        let lo = self.token.span;
        let krate = Ok(ast::Crate {
            attrs: self.parse_inner_attributes()?,
            module: self.parse_mod_items(&token::Eof, lo)?,
            span: lo.to(self.token.span),
            // Filled in by proc_macro_harness::inject()
            proc_macros: Vec::new(),
        });
        krate
    }

    /// Parses a `mod <foo> { ... }` or `mod <foo>;` item.
    pub(super) fn parse_item_mod(&mut self, attrs: &mut Vec<Attribute>) -> PResult<'a, ItemInfo> {
        let in_cfg = crate::config::process_configure_mod(self.sess, self.cfg_mods, attrs);

        let id_span = self.token.span;
        let id = self.parse_ident()?;
        let (module, mut inner_attrs) = if self.eat(&token::Semi) {
            if in_cfg && self.recurse_into_file_modules {
                // This mod is in an external file. Let's go get it!
                let ModulePathSuccess { path, directory_ownership } =
                    self.submod_path(id, &attrs, id_span)?;
                self.eval_src_mod(path, directory_ownership, id.to_string(), id_span)?
            } else {
                (ast::Mod { inner: DUMMY_SP, items: Vec::new(), inline: false }, Vec::new())
            }
        } else {
            let old_directory = self.directory.clone();
            self.push_directory(id, &attrs);

            self.expect(&token::OpenDelim(token::Brace))?;
            let mod_inner_lo = self.token.span;
            let inner_attrs = self.parse_inner_attributes()?;
            let module = self.parse_mod_items(&token::CloseDelim(token::Brace), mod_inner_lo)?;

            self.directory = old_directory;
            (module, inner_attrs)
        };
        attrs.append(&mut inner_attrs);
        Ok((id, ItemKind::Mod(module)))
    }

    /// Given a termination token, parses all of the items in a module.
    fn parse_mod_items(&mut self, term: &TokenKind, inner_lo: Span) -> PResult<'a, Mod> {
        let mut items = vec![];
        while let Some(item) = self.parse_item()? {
            items.push(item);
            self.maybe_consume_incorrect_semicolon(&items);
        }

        if !self.eat(term) {
            let token_str = super::token_descr(&self.token);
            if !self.maybe_consume_incorrect_semicolon(&items) {
                let msg = &format!("expected item, found {}", token_str);
                let mut err = self.struct_span_err(self.token.span, msg);
                err.span_label(self.token.span, "expected item");
                return Err(err);
            }
        }

        let hi = if self.token.span.is_dummy() { inner_lo } else { self.prev_token.span };

        Ok(Mod { inner: inner_lo.to(hi), items, inline: true })
    }

    fn submod_path(
        &mut self,
        id: ast::Ident,
        outer_attrs: &[Attribute],
        id_sp: Span,
    ) -> PResult<'a, ModulePathSuccess> {
        if let Some(path) = Parser::submod_path_from_attr(outer_attrs, &self.directory.path) {
            let directory_ownership = match path.file_name().and_then(|s| s.to_str()) {
                // All `#[path]` files are treated as though they are a `mod.rs` file.
                // This means that `mod foo;` declarations inside `#[path]`-included
                // files are siblings,
                //
                // Note that this will produce weirdness when a file named `foo.rs` is
                // `#[path]` included and contains a `mod foo;` declaration.
                // If you encounter this, it's your own darn fault :P
                Some(_) => DirectoryOwnership::Owned { relative: None },
                _ => DirectoryOwnership::UnownedViaMod,
            };
            return Ok(ModulePathSuccess { directory_ownership, path });
        }

        let relative = match self.directory.ownership {
            DirectoryOwnership::Owned { relative } => relative,
            DirectoryOwnership::UnownedViaBlock | DirectoryOwnership::UnownedViaMod => None,
        };
        let paths =
            Parser::default_submod_path(id, relative, &self.directory.path, self.sess.source_map());

        match self.directory.ownership {
            DirectoryOwnership::Owned { .. } => {
                paths.result.map_err(|err| self.span_fatal_err(id_sp, err))
            }
            DirectoryOwnership::UnownedViaBlock => self.error_decl_mod_in_block(id_sp, paths),
            DirectoryOwnership::UnownedViaMod => self.error_cannot_declare_mod_here(id_sp, paths),
        }
    }

    fn error_decl_mod_in_block<T>(&self, id_sp: Span, paths: ModulePath) -> PResult<'a, T> {
        let msg =
            "Cannot declare a non-inline module inside a block unless it has a path attribute";
        let mut err = self.struct_span_err(id_sp, msg);
        if paths.path_exists {
            let msg = format!("Maybe `use` the module `{}` instead of redeclaring it", paths.name);
            err.span_note(id_sp, &msg);
        }
        Err(err)
    }

    fn error_cannot_declare_mod_here<T>(&self, id_sp: Span, paths: ModulePath) -> PResult<'a, T> {
        let mut err = self.struct_span_err(id_sp, "cannot declare a new module at this location");
        if !id_sp.is_dummy() {
            if let FileName::Real(src_path) = self.sess.source_map().span_to_filename(id_sp) {
                if let Some(stem) = src_path.file_stem() {
                    let mut dest_path = src_path.clone();
                    dest_path.set_file_name(stem);
                    dest_path.push("mod.rs");
                    err.span_note(
                        id_sp,
                        &format!(
                            "maybe move this module `{}` to its own \
                                    directory via `{}`",
                            src_path.display(),
                            dest_path.display()
                        ),
                    );
                }
            }
        }
        if paths.path_exists {
            err.span_note(
                id_sp,
                &format!(
                    "... or maybe `use` the module `{}` instead \
                                of possibly redeclaring it",
                    paths.name
                ),
            );
        }
        Err(err)
    }

    /// Derive a submodule path from the first found `#[path = "path_string"]`.
    /// The provided `dir_path` is joined with the `path_string`.
    // Public for rustfmt usage.
    pub fn submod_path_from_attr(attrs: &[Attribute], dir_path: &Path) -> Option<PathBuf> {
        // Extract path string from first `#[path = "path_string"]` attribute.
        let path_string = attr::first_attr_value_str_by_name(attrs, sym::path)?;
        let path_string = path_string.as_str();

        // On windows, the base path might have the form
        // `\\?\foo\bar` in which case it does not tolerate
        // mixed `/` and `\` separators, so canonicalize
        // `/` to `\`.
        #[cfg(windows)]
        let path_string = path_string.replace("/", "\\");

        Some(dir_path.join(&*path_string))
    }

    /// Returns a path to a module.
    // Public for rustfmt usage.
    pub fn default_submod_path(
        id: ast::Ident,
        relative: Option<ast::Ident>,
        dir_path: &Path,
        source_map: &SourceMap,
    ) -> ModulePath {
        // If we're in a foo.rs file instead of a mod.rs file,
        // we need to look for submodules in
        // `./foo/<id>.rs` and `./foo/<id>/mod.rs` rather than
        // `./<id>.rs` and `./<id>/mod.rs`.
        let relative_prefix_string;
        let relative_prefix = if let Some(ident) = relative {
            relative_prefix_string = format!("{}{}", ident.name, path::MAIN_SEPARATOR);
            &relative_prefix_string
        } else {
            ""
        };

        let mod_name = id.name.to_string();
        let default_path_str = format!("{}{}.rs", relative_prefix, mod_name);
        let secondary_path_str =
            format!("{}{}{}mod.rs", relative_prefix, mod_name, path::MAIN_SEPARATOR);
        let default_path = dir_path.join(&default_path_str);
        let secondary_path = dir_path.join(&secondary_path_str);
        let default_exists = source_map.file_exists(&default_path);
        let secondary_exists = source_map.file_exists(&secondary_path);

        let result = match (default_exists, secondary_exists) {
            (true, false) => Ok(ModulePathSuccess {
                path: default_path,
                directory_ownership: DirectoryOwnership::Owned { relative: Some(id) },
            }),
            (false, true) => Ok(ModulePathSuccess {
                path: secondary_path,
                directory_ownership: DirectoryOwnership::Owned { relative: None },
            }),
            (false, false) => {
                Err(Error::FileNotFoundForModule { mod_name: mod_name.clone(), default_path })
            }
            (true, true) => Err(Error::DuplicatePaths {
                mod_name: mod_name.clone(),
                default_path: default_path_str,
                secondary_path: secondary_path_str,
            }),
        };

        ModulePath { name: mod_name, path_exists: default_exists || secondary_exists, result }
    }

    /// Reads a module from a source file.
    fn eval_src_mod(
        &mut self,
        path: PathBuf,
        directory_ownership: DirectoryOwnership,
        name: String,
        id_sp: Span,
    ) -> PResult<'a, (Mod, Vec<Attribute>)> {
        let mut included_mod_stack = self.sess.included_mod_stack.borrow_mut();
        if let Some(i) = included_mod_stack.iter().position(|p| *p == path) {
            let mut err = String::from("circular modules: ");
            let len = included_mod_stack.len();
            for p in &included_mod_stack[i..len] {
                err.push_str(&p.to_string_lossy());
                err.push_str(" -> ");
            }
            err.push_str(&path.to_string_lossy());
            return Err(self.struct_span_err(id_sp, &err[..]));
        }
        included_mod_stack.push(path.clone());
        drop(included_mod_stack);

        let mut p0 =
            new_sub_parser_from_file(self.sess, &path, directory_ownership, Some(name), id_sp);
        p0.cfg_mods = self.cfg_mods;
        let mod_inner_lo = p0.token.span;
        let mod_attrs = p0.parse_inner_attributes()?;
        let mut m0 = p0.parse_mod_items(&token::Eof, mod_inner_lo)?;
        m0.inline = false;
        self.sess.included_mod_stack.borrow_mut().pop();
        Ok((m0, mod_attrs))
    }

    fn push_directory(&mut self, id: Ident, attrs: &[Attribute]) {
        if let Some(path) = attr::first_attr_value_str_by_name(attrs, sym::path) {
            self.directory.path.push(&*path.as_str());
            self.directory.ownership = DirectoryOwnership::Owned { relative: None };
        } else {
            // We have to push on the current module name in the case of relative
            // paths in order to ensure that any additional module paths from inline
            // `mod x { ... }` come after the relative extension.
            //
            // For example, a `mod z { ... }` inside `x/y.rs` should set the current
            // directory path to `/x/y/z`, not `/x/z` with a relative offset of `y`.
            if let DirectoryOwnership::Owned { relative } = &mut self.directory.ownership {
                if let Some(ident) = relative.take() {
                    // remove the relative offset
                    self.directory.path.push(&*ident.as_str());
                }
            }
            self.directory.path.push(&*id.as_str());
        }
    }
}
<|endoftext|>


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

//! Implementation of Rust stack unwinding
//!
//! For background on exception handling and stack unwinding please see
//! "Exception Handling in LLVM" (llvm.org/docs/ExceptionHandling.html) and
//! documents linked from it.
//! These are also good reads:
//!     http://mentorembedded.github.io/cxx-abi/abi-eh.html
//!     http://monoinfinito.wordpress.com/series/exception-handling-in-c/
//!     http://www.airs.com/blog/index.php?s=exception+frames
//!
//! ## A brief summary
//!
//! Exception handling happens in two phases: a search phase and a cleanup phase.
//!
//! In both phases the unwinder walks stack frames from top to bottom using
//! information from the stack frame unwind sections of the current process's
//! modules ("module" here refers to an OS module, i.e. an executable or a
//! dynamic library).
//!
//! For each stack frame, it invokes the associated "personality routine", whose
//! address is also stored in the unwind info section.
//!
//! In the search phase, the job of a personality routine is to examine exception
//! object being thrown, and to decide whether it should be caught at that stack
//! frame.  Once the handler frame has been identified, cleanup phase begins.
//!
//! In the cleanup phase, personality routines invoke cleanup code associated
//! with their stack frames (i.e. destructors).  Once stack has been unwound down
//! to the handler frame level, unwinding stops and the last personality routine
//! transfers control to its catch block.
//!
//! ## Frame unwind info registration
//!
//! Each module has its own frame unwind info section (usually ".eh_frame"), and
//! unwinder needs to know about all of them in order for unwinding to be able to
//! cross module boundaries.
//!
//! On some platforms, like Linux, this is achieved by dynamically enumerating
//! currently loaded modules via the dl_iterate_phdr() API and finding all
//! .eh_frame sections.
//!
//! Others, like Windows, require modules to actively register their unwind info
//! sections by calling __register_frame_info() API at startup.  In the latter
//! case it is essential that there is only one copy of the unwinder runtime in
//! the process.  This is usually achieved by linking to the dynamic version of
//! the unwind runtime.
//!
//! Currently Rust uses unwind runtime provided by libgcc.

#![allow(dead_code)]
#![allow(unused_imports)]

use prelude::v1::*;

use any::Any;
use boxed;
use cell::Cell;
use cmp;
use panicking;
use fmt;
use intrinsics;
use mem;
use sync::atomic::{self, Ordering};
use sys_common::mutex::Mutex;

// The actual unwinding implementation is cfg'd here, and we've got two current
// implementations. One goes through SEH on Windows and the other goes through
// libgcc via the libunwind-like API.

// i686-pc-windows-msvc
#[cfg(all(windows, target_arch = "x86", target_env = "msvc"))]
#[path = "seh.rs"] #[doc(hidden)]
pub mod imp;

// x86_64-pc-windows-*
#[cfg(all(windows, target_arch = "x86_64"))]
#[path = "seh64_gnu.rs"] #[doc(hidden)]
pub mod imp;

// i686-pc-windows-gnu and all others
#[cfg(any(unix, all(windows, target_arch = "x86", target_env = "gnu")))]
#[path = "gcc.rs"] #[doc(hidden)]
pub mod imp;

pub type Callback = fn(msg: &(Any + Send), file: &'static str, line: u32);

// Variables used for invoking callbacks when a thread starts to unwind.
//
// For more information, see below.
const MAX_CALLBACKS: usize = 16;
static CALLBACKS: [atomic::AtomicUsize; MAX_CALLBACKS] =
        [atomic::AtomicUsize::new(0), atomic::AtomicUsize::new(0),
         atomic::AtomicUsize::new(0), atomic::AtomicUsize::new(0),
         atomic::AtomicUsize::new(0), atomic::AtomicUsize::new(0),
         atomic::AtomicUsize::new(0), atomic::AtomicUsize::new(0),
         atomic::AtomicUsize::new(0), atomic::AtomicUsize::new(0),
         atomic::AtomicUsize::new(0), atomic::AtomicUsize::new(0),
         atomic::AtomicUsize::new(0), atomic::AtomicUsize::new(0),
         atomic::AtomicUsize::new(0), atomic::AtomicUsize::new(0)];
static CALLBACK_CNT: atomic::AtomicUsize = atomic::AtomicUsize::new(0);

thread_local! { static PANICKING: Cell<bool> = Cell::new(false) }

/// Invoke a closure, capturing the cause of panic if one occurs.
///
/// This function will return `Ok(())` if the closure did not panic, and will
/// return `Err(cause)` if the closure panics. The `cause` returned is the
/// object with which panic was originally invoked.
///
/// This function also is unsafe for a variety of reasons:
///
/// * This is not safe to call in a nested fashion. The unwinding
///   interface for Rust is designed to have at most one try/catch block per
///   thread, not multiple. No runtime checking is currently performed to uphold
///   this invariant, so this function is not safe. A nested try/catch block
///   may result in corruption of the outer try/catch block's state, especially
///   if this is used within a thread itself.
///
/// * It is not sound to trigger unwinding while already unwinding. Rust threads
///   have runtime checks in place to ensure this invariant, but it is not
///   guaranteed that a rust thread is in place when invoking this function.
///   Unwinding twice can lead to resource leaks where some destructors are not
///   run.
pub unsafe fn try<F: FnOnce()>(f: F) -> Result<(), Box<Any + Send>> {
    let mut f = Some(f);
    return inner_try(try_fn::<F>, &mut f as *mut _ as *mut u8);

    // If an inner function were not used here, then this generic function `try`
    // uses the native symbol `rust_try`, for which the code is statically
    // linked into the standard library. This means that the DLL for the
    // standard library must have `rust_try` as an exposed symbol that
    // downstream crates can link against (because monomorphizations of `try` in
    // downstream crates will have a reference to the `rust_try` symbol).
    //
    // On MSVC this requires the symbol `rust_try` to be tagged with
    // `dllexport`, but it's easier to not have conditional `src/rt/rust_try.ll`
    // files and instead just have this non-generic shim the compiler can take
    // care of exposing correctly.
    unsafe fn inner_try(f: fn(*mut u8), data: *mut u8)
                        -> Result<(), Box<Any + Send>> {
        PANICKING.with(|s| {
            let prev = s.get();
            s.set(false);
            let ep = intrinsics::try(f, data);
            s.set(prev);
            if ep.is_null() {
                Ok(())
            } else {
                Err(imp::cleanup(ep))
            }
        })
    }

    fn try_fn<F: FnOnce()>(opt_closure: *mut u8) {
        let opt_closure = opt_closure as *mut Option<F>;
        unsafe { (*opt_closure).take().unwrap()(); }
    }

    extern {
        // Rust's try-catch
        // When f(...) returns normally, the return value is null.
        // When f(...) throws, the return value is a pointer to the caught
        // exception object.
        fn rust_try(f: extern fn(*mut u8),
                    data: *mut u8) -> *mut u8;
    }
}

/// Determines whether the current thread is unwinding because of panic.
pub fn panicking() -> bool {
    PANICKING.with(|s| s.get())
}

// An uninlined, unmangled function upon which to slap yer breakpoints
#[inline(never)]
#[no_mangle]
#[allow(private_no_mangle_fns)]
fn rust_panic(cause: Box<Any + Send + 'static>) -> ! {
    unsafe {
        imp::panic(cause)
    }
}

#[cfg(not(test))]
/// Entry point of panic from the libcore crate.
#[lang = "panic_fmt"]
#[unwind]
pub extern fn rust_begin_unwind(msg: fmt::Arguments,
                                file: &'static str, line: u32) -> ! {
    begin_unwind_fmt(msg, &(file, line))
}

/// The entry point for unwinding with a formatted message.
///
/// This is designed to reduce the amount of code required at the call
/// site as much as possible (so that `panic!()` has as low an impact
/// on (e.g.) the inlining of other functions as possible), by moving
/// the actual formatting into this shared place.
#[inline(never)] #[cold]
pub fn begin_unwind_fmt(msg: fmt::Arguments, file_line: &(&'static str, u32)) -> ! {
    use fmt::Write;

    // We do two allocations here, unfortunately. But (a) they're
    // required with the current scheme, and (b) we don't handle
    // panic + OOM properly anyway (see comment in begin_unwind
    // below).

    let mut s = String::new();
    let _ = s.write_fmt(msg);
    begin_unwind_inner(Box::new(s), file_line)
}

/// This is the entry point of unwinding for panic!() and assert!().
#[inline(never)] #[cold] // avoid code bloat at the call sites as much as possible
pub fn begin_unwind<M: Any + Send>(msg: M, file_line: &(&'static str, u32)) -> ! {
    // Note that this should be the only allocation performed in this code path.
    // Currently this means that panic!() on OOM will invoke this code path,
    // but then again we're not really ready for panic on OOM anyway. If
    // we do start doing this, then we should propagate this allocation to
    // be performed in the parent of this thread instead of the thread that's
    // panicking.

    // see below for why we do the `Any` coercion here.
    begin_unwind_inner(Box::new(msg), file_line)
}

/// The core of the unwinding.
///
/// This is non-generic to avoid instantiation bloat in other crates
/// (which makes compilation of small crates noticeably slower). (Note:
/// we need the `Any` object anyway, we're not just creating it to
/// avoid being generic.)
///
/// Doing this split took the LLVM IR line counts of `fn main() { panic!()
/// }` from ~1900/3700 (-O/no opts) to 180/590.
#[inline(never)] #[cold] // this is the slow path, please never inline this
fn begin_unwind_inner(msg: Box<Any + Send>,
                      file_line: &(&'static str, u32)) -> ! {
    // Make sure the default failure handler is registered before we look at the
    // callbacks. We also use a raw sys-based mutex here instead of a
    // `std::sync` one as accessing TLS can cause weird recursive problems (and
    // we don't need poison checking).
    unsafe {
        static LOCK: Mutex = Mutex::new();
        static mut INIT: bool = false;
        LOCK.lock();
        if !INIT {
            register(panicking::on_panic);
            INIT = true;
        }
        LOCK.unlock();
    }

    // First, invoke call the user-defined callbacks triggered on thread panic.
    //
    // By the time that we see a callback has been registered (by reading
    // MAX_CALLBACKS), the actual callback itself may have not been stored yet,
    // so we just chalk it up to a race condition and move on to the next
    // callback. Additionally, CALLBACK_CNT may briefly be higher than
    // MAX_CALLBACKS, so we're sure to clamp it as necessary.
    let callbacks = {
        let amt = CALLBACK_CNT.load(Ordering::SeqCst);
        &CALLBACKS[..cmp::min(amt, MAX_CALLBACKS)]
    };
    for cb in callbacks {
        match cb.load(Ordering::SeqCst) {
            0 => {}
            n => {
                let f: Callback = unsafe { mem::transmute(n) };
                let (file, line) = *file_line;
                f(&*msg, file, line);
            }
        }
    };

    // Now that we've run all the necessary unwind callbacks, we actually
    // perform the unwinding.
    if panicking() {
        // If a thread panics while it's already unwinding then we
        // have limited options. Currently our preference is to
        // just abort. In the future we may consider resuming
        // unwinding or otherwise exiting the thread cleanly.
        super::util::dumb_print(format_args!("thread panicked while panicking. \
                                              aborting."));
        unsafe { intrinsics::abort() }
    }
    PANICKING.with(|s| s.set(true));
    rust_panic(msg);
}

/// Register a callback to be invoked when a thread unwinds.
///
/// This is an unsafe and experimental API which allows for an arbitrary
/// callback to be invoked when a thread panics. This callback is invoked on both
/// the initial unwinding and a double unwinding if one occurs. Additionally,
/// the local `Thread` will be in place for the duration of the callback, and
/// the callback must ensure that it remains in place once the callback returns.
///
/// Only a limited number of callbacks can be registered, and this function
/// returns whether the callback was successfully registered or not. It is not
/// currently possible to unregister a callback once it has been registered.
pub unsafe fn register(f: Callback) -> bool {
    match CALLBACK_CNT.fetch_add(1, Ordering::SeqCst) {
        // The invocation code has knowledge of this window where the count has
        // been incremented, but the callback has not been stored. We're
        // guaranteed that the slot we're storing into is 0.
        n if n < MAX_CALLBACKS => {
            let prev = CALLBACKS[n].swap(mem::transmute(f), Ordering::SeqCst);
            rtassert!(prev == 0);
            true
        }
        // If we accidentally bumped the count too high, pull it back.
        _ => {
            CALLBACK_CNT.store(MAX_CALLBACKS, Ordering::SeqCst);
            false
        }
    }
}
<commit_msg>Auto merge of #28585 - ranma42:simpler-panic, r=alexcrichton<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Implementation of Rust stack unwinding
//!
//! For background on exception handling and stack unwinding please see
//! "Exception Handling in LLVM" (llvm.org/docs/ExceptionHandling.html) and
//! documents linked from it.
//! These are also good reads:
//!     http://mentorembedded.github.io/cxx-abi/abi-eh.html
//!     http://monoinfinito.wordpress.com/series/exception-handling-in-c/
//!     http://www.airs.com/blog/index.php?s=exception+frames
//!
//! ## A brief summary
//!
//! Exception handling happens in two phases: a search phase and a cleanup phase.
//!
//! In both phases the unwinder walks stack frames from top to bottom using
//! information from the stack frame unwind sections of the current process's
//! modules ("module" here refers to an OS module, i.e. an executable or a
//! dynamic library).
//!
//! For each stack frame, it invokes the associated "personality routine", whose
//! address is also stored in the unwind info section.
//!
//! In the search phase, the job of a personality routine is to examine exception
//! object being thrown, and to decide whether it should be caught at that stack
//! frame.  Once the handler frame has been identified, cleanup phase begins.
//!
//! In the cleanup phase, personality routines invoke cleanup code associated
//! with their stack frames (i.e. destructors).  Once stack has been unwound down
//! to the handler frame level, unwinding stops and the last personality routine
//! transfers control to its catch block.
//!
//! ## Frame unwind info registration
//!
//! Each module has its own frame unwind info section (usually ".eh_frame"), and
//! unwinder needs to know about all of them in order for unwinding to be able to
//! cross module boundaries.
//!
//! On some platforms, like Linux, this is achieved by dynamically enumerating
//! currently loaded modules via the dl_iterate_phdr() API and finding all
//! .eh_frame sections.
//!
//! Others, like Windows, require modules to actively register their unwind info
//! sections by calling __register_frame_info() API at startup.  In the latter
//! case it is essential that there is only one copy of the unwinder runtime in
//! the process.  This is usually achieved by linking to the dynamic version of
//! the unwind runtime.
//!
//! Currently Rust uses unwind runtime provided by libgcc.

#![allow(dead_code)]
#![allow(unused_imports)]

use prelude::v1::*;

use any::Any;
use boxed;
use cell::Cell;
use cmp;
use panicking;
use fmt;
use intrinsics;
use mem;
use sync::atomic::{self, Ordering};
use sys_common::mutex::Mutex;

// The actual unwinding implementation is cfg'd here, and we've got two current
// implementations. One goes through SEH on Windows and the other goes through
// libgcc via the libunwind-like API.

// i686-pc-windows-msvc
#[cfg(all(windows, target_arch = "x86", target_env = "msvc"))]
#[path = "seh.rs"] #[doc(hidden)]
pub mod imp;

// x86_64-pc-windows-*
#[cfg(all(windows, target_arch = "x86_64"))]
#[path = "seh64_gnu.rs"] #[doc(hidden)]
pub mod imp;

// i686-pc-windows-gnu and all others
#[cfg(any(unix, all(windows, target_arch = "x86", target_env = "gnu")))]
#[path = "gcc.rs"] #[doc(hidden)]
pub mod imp;

thread_local! { static PANICKING: Cell<bool> = Cell::new(false) }

/// Invoke a closure, capturing the cause of panic if one occurs.
///
/// This function will return `Ok(())` if the closure did not panic, and will
/// return `Err(cause)` if the closure panics. The `cause` returned is the
/// object with which panic was originally invoked.
///
/// This function also is unsafe for a variety of reasons:
///
/// * This is not safe to call in a nested fashion. The unwinding
///   interface for Rust is designed to have at most one try/catch block per
///   thread, not multiple. No runtime checking is currently performed to uphold
///   this invariant, so this function is not safe. A nested try/catch block
///   may result in corruption of the outer try/catch block's state, especially
///   if this is used within a thread itself.
///
/// * It is not sound to trigger unwinding while already unwinding. Rust threads
///   have runtime checks in place to ensure this invariant, but it is not
///   guaranteed that a rust thread is in place when invoking this function.
///   Unwinding twice can lead to resource leaks where some destructors are not
///   run.
pub unsafe fn try<F: FnOnce()>(f: F) -> Result<(), Box<Any + Send>> {
    let mut f = Some(f);
    return inner_try(try_fn::<F>, &mut f as *mut _ as *mut u8);

    // If an inner function were not used here, then this generic function `try`
    // uses the native symbol `rust_try`, for which the code is statically
    // linked into the standard library. This means that the DLL for the
    // standard library must have `rust_try` as an exposed symbol that
    // downstream crates can link against (because monomorphizations of `try` in
    // downstream crates will have a reference to the `rust_try` symbol).
    //
    // On MSVC this requires the symbol `rust_try` to be tagged with
    // `dllexport`, but it's easier to not have conditional `src/rt/rust_try.ll`
    // files and instead just have this non-generic shim the compiler can take
    // care of exposing correctly.
    unsafe fn inner_try(f: fn(*mut u8), data: *mut u8)
                        -> Result<(), Box<Any + Send>> {
        PANICKING.with(|s| {
            let prev = s.get();
            s.set(false);
            let ep = intrinsics::try(f, data);
            s.set(prev);
            if ep.is_null() {
                Ok(())
            } else {
                Err(imp::cleanup(ep))
            }
        })
    }

    fn try_fn<F: FnOnce()>(opt_closure: *mut u8) {
        let opt_closure = opt_closure as *mut Option<F>;
        unsafe { (*opt_closure).take().unwrap()(); }
    }

    extern {
        // Rust's try-catch
        // When f(...) returns normally, the return value is null.
        // When f(...) throws, the return value is a pointer to the caught
        // exception object.
        fn rust_try(f: extern fn(*mut u8),
                    data: *mut u8) -> *mut u8;
    }
}

/// Determines whether the current thread is unwinding because of panic.
pub fn panicking() -> bool {
    PANICKING.with(|s| s.get())
}

// An uninlined, unmangled function upon which to slap yer breakpoints
#[inline(never)]
#[no_mangle]
#[allow(private_no_mangle_fns)]
fn rust_panic(cause: Box<Any + Send + 'static>) -> ! {
    unsafe {
        imp::panic(cause)
    }
}

#[cfg(not(test))]
/// Entry point of panic from the libcore crate.
#[lang = "panic_fmt"]
#[unwind]
pub extern fn rust_begin_unwind(msg: fmt::Arguments,
                                file: &'static str, line: u32) -> ! {
    begin_unwind_fmt(msg, &(file, line))
}

/// The entry point for unwinding with a formatted message.
///
/// This is designed to reduce the amount of code required at the call
/// site as much as possible (so that `panic!()` has as low an impact
/// on (e.g.) the inlining of other functions as possible), by moving
/// the actual formatting into this shared place.
#[inline(never)] #[cold]
pub fn begin_unwind_fmt(msg: fmt::Arguments, file_line: &(&'static str, u32)) -> ! {
    use fmt::Write;

    // We do two allocations here, unfortunately. But (a) they're
    // required with the current scheme, and (b) we don't handle
    // panic + OOM properly anyway (see comment in begin_unwind
    // below).

    let mut s = String::new();
    let _ = s.write_fmt(msg);
    begin_unwind_inner(Box::new(s), file_line)
}

/// This is the entry point of unwinding for panic!() and assert!().
#[inline(never)] #[cold] // avoid code bloat at the call sites as much as possible
pub fn begin_unwind<M: Any + Send>(msg: M, file_line: &(&'static str, u32)) -> ! {
    // Note that this should be the only allocation performed in this code path.
    // Currently this means that panic!() on OOM will invoke this code path,
    // but then again we're not really ready for panic on OOM anyway. If
    // we do start doing this, then we should propagate this allocation to
    // be performed in the parent of this thread instead of the thread that's
    // panicking.

    // see below for why we do the `Any` coercion here.
    begin_unwind_inner(Box::new(msg), file_line)
}

/// The core of the unwinding.
///
/// This is non-generic to avoid instantiation bloat in other crates
/// (which makes compilation of small crates noticeably slower). (Note:
/// we need the `Any` object anyway, we're not just creating it to
/// avoid being generic.)
///
/// Doing this split took the LLVM IR line counts of `fn main() { panic!()
/// }` from ~1900/3700 (-O/no opts) to 180/590.
#[inline(never)] #[cold] // this is the slow path, please never inline this
fn begin_unwind_inner(msg: Box<Any + Send>,
                      file_line: &(&'static str, u32)) -> ! {
    let (file, line) = *file_line;

    // First, invoke the default panic handler.
    panicking::on_panic(&*msg, file, line);

    if panicking() {
        // If a thread panics while it's already unwinding then we
        // have limited options. Currently our preference is to
        // just abort. In the future we may consider resuming
        // unwinding or otherwise exiting the thread cleanly.
        super::util::dumb_print(format_args!("thread panicked while panicking. \
                                              aborting."));
        unsafe { intrinsics::abort() }
    }
    PANICKING.with(|s| s.set(true));

    // Finally, perform the unwinding.
    rust_panic(msg);
}
<|endoftext|>


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

use std::path::{self, Path, PathBuf};
use std::ffi::OsString;

// Unfortunately, on windows, gcc cannot accept paths of the form `\\?\C:\...`
// (a verbatim path). This form of path is generally pretty rare, but the
// implementation of `fs::canonicalize` currently generates paths of this form,
// meaning that we're going to be passing quite a few of these down to gcc.
//
// For now we just strip the "verbatim prefix" of `\\?\` from the path. This
// will probably lose information in some cases, but there's not a whole lot
// more we can do with a buggy gcc...
pub fn fix_windows_verbatim_for_gcc(p: &Path) -> PathBuf {
    if !cfg!(windows) {
        return p.to_path_buf()
    }
    let mut components = p.components();
    let prefix = match components.next() {
        Some(path::Component::Prefix(p)) => p,
        _ => return p.to_path_buf(),
    };
    let disk = match prefix.kind() {
        path::Prefix::VerbatimDisk(disk) => disk,
        _ => return p.to_path_buf(),
    };
    let mut base = OsString::from(format!("{}:", disk as char));
    base.push(components.as_path());
    PathBuf::from(base)
}
<commit_msg>rustc: Fixup verbatim UNC paths as well on Windows<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::path::{self, Path, PathBuf};
use std::ffi::OsString;

// Unfortunately, on windows, it looks like msvcrt.dll is silently translating
// verbatim paths under the hood to non-verbatim paths! This manifests itself as
// gcc looking like it cannot accept paths of the form `\\?\C:\...`, but the
// real bug seems to lie in msvcrt.dll.
//
// Verbatim paths are generally pretty rare, but the implementation of
// `fs::canonicalize` currently generates paths of this form, meaning that we're
// going to be passing quite a few of these down to gcc, so we need to deal with
// this case.
//
// For now we just strip the "verbatim prefix" of `\\?\` from the path. This
// will probably lose information in some cases, but there's not a whole lot
// more we can do with a buggy msvcrt...
//
// For some more information, see this comment:
//   https://github.com/rust-lang/rust/issues/25505#issuecomment-102876737
pub fn fix_windows_verbatim_for_gcc(p: &Path) -> PathBuf {
    if !cfg!(windows) {
        return p.to_path_buf()
    }
    let mut components = p.components();
    let prefix = match components.next() {
        Some(path::Component::Prefix(p)) => p,
        _ => return p.to_path_buf(),
    };
    match prefix.kind() {
        path::Prefix::VerbatimDisk(disk) => {
            let mut base = OsString::from(format!("{}:", disk as char));
            base.push(components.as_path());
            PathBuf::from(base)
        }
        path::Prefix::VerbatimUNC(server, share) => {
            let mut base = OsString::from(r"\\");
            base.push(server);
            base.push(r"\");
            base.push(share);
            base.push(components.as_path());
            PathBuf::from(base)
        }
        _ => p.to_path_buf(),
    }
}
<|endoftext|>


<commit_before>// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

use crate::response::BadRequestError;
use aptos_api_types::AptosErrorCode;
use serde::Deserialize;

const DEFAULT_PAGE_SIZE: u16 = 25;
const MAX_PAGE_SIZE: u16 = 1000;

#[derive(Clone, Debug, Deserialize)]
pub(crate) struct Page {
    start: Option<u64>,
    limit: Option<u16>,
}

impl Page {
    pub fn new(start: Option<u64>, limit: Option<u16>) -> Self {
        Self { start, limit }
    }

    pub fn compute_start<E: BadRequestError>(&self, limit: u16, max: u64) -> Result<u64, E> {
        let last_page_start = max.saturating_sub((limit.saturating_sub(1)) as u64);
        self.start(last_page_start, max)
    }

    pub fn start<E: BadRequestError>(&self, default: u64, max: u64) -> Result<u64, E> {
        let start = self.start.unwrap_or(default);
        if start > max {
            return Err(E::bad_request_str(&format!(
                "Given start value ({}) is higher than the current ledger version, it must be < {}",
                start, max
            ))
            .error_code(AptosErrorCode::InvalidStartParam));
        }
        Ok(start)
    }

    pub fn start_option(&self) -> Option<u64> {
        self.start
    }

    pub fn limit<E: BadRequestError>(&self) -> Result<u16, E> {
        let limit = self.limit.unwrap_or(DEFAULT_PAGE_SIZE);
        if limit == 0 {
            return Err(E::bad_request_str(&format!(
                "Given limit value ({}) must not be zero",
                limit
            ))
            .error_code(AptosErrorCode::InvalidLimitParam));
        }
        if limit > MAX_PAGE_SIZE {
            return Err(E::bad_request_str(&format!(
                "Given limit value ({}) is too large, it must be < {}",
                limit, MAX_PAGE_SIZE
            ))
            .error_code(AptosErrorCode::InvalidLimitParam));
        }
        Ok(limit)
    }
}
<commit_msg>[api] Add error codes to page operations<commit_after>// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

use crate::response::BadRequestError;
use aptos_api_types::AptosErrorCode;
use serde::Deserialize;

const DEFAULT_PAGE_SIZE: u16 = 25;
const MAX_PAGE_SIZE: u16 = 1000;

#[derive(Clone, Debug, Deserialize)]
pub(crate) struct Page {
    start: Option<u64>,
    limit: Option<u16>,
}

impl Page {
    pub fn new(start: Option<u64>, limit: Option<u16>) -> Self {
        Self { start, limit }
    }

    pub fn compute_start<E: BadRequestError>(&self, limit: u16, max: u64) -> Result<u64, E> {
        let last_page_start = max.saturating_sub((limit.saturating_sub(1)) as u64);
        self.start(last_page_start, max)
    }

    pub fn start<E: BadRequestError>(&self, default: u64, max: u64) -> Result<u64, E> {
        let start = self.start.unwrap_or(default);
        if start > max {
            return Err(E::bad_request_with_code(
                &format!(
                "Given start value ({}) is higher than the current ledger version, it must be < {}",
                start, max
            ),
                AptosErrorCode::InvalidStartParam,
            ));
        }
        Ok(start)
    }

    pub fn start_option(&self) -> Option<u64> {
        self.start
    }

    pub fn limit<E: BadRequestError>(&self) -> Result<u16, E> {
        let limit = self.limit.unwrap_or(DEFAULT_PAGE_SIZE);
        if limit == 0 {
            return Err(E::bad_request_with_code(
                &format!("Given limit value ({}) must not be zero", limit),
                AptosErrorCode::InvalidLimitParam,
            ));
        }
        if limit > MAX_PAGE_SIZE {
            return Err(E::bad_request_with_code(
                &format!(
                    "Given limit value ({}) is too large, it must be < {}",
                    limit, MAX_PAGE_SIZE
                ),
                AptosErrorCode::InvalidLimitParam,
            ));
        }
        Ok(limit)
    }
}
<|endoftext|>


<commit_before>use std::rc::Rc;
use std::collections::{VecDeque, HashMap};

use parser::Identifier;
use memory::{StaticAllocator, MemoryBlock};

use super::operation::Operation;
use super::item_type::{ItemType, FunctionTypeDef, FuncArgs};

/// Represents a single item in a scope
pub struct ScopeItem {
    pub type_def: ItemType,
    pub memory: MemoryBlock,
}

/// Represents a single level of scope
pub type Scope = HashMap<String, ScopeItem>;

pub struct ScopeStack {
    stack: VecDeque<Scope>,
    allocator: StaticAllocator,
}

impl ScopeStack {
    pub fn new() -> ScopeStack {
        ScopeStack {
            stack: {
                let mut queue = VecDeque::new();
                queue.push_back(Scope::new());
                queue
            },
            allocator: StaticAllocator::new(),
        }
    }

    /// Pushes a new level of scope onto the stack
    /// This scope will become the current scope
    pub fn push_scope(&mut self) {
        self.stack.push_back(Scope::new());
    }

    /// Removes and returns the top level scope (current scope)
    ///
    /// # Panics
    /// Panics if there is no scope in the stack
    pub fn pop_scope(&mut self) -> Scope {
        self.stack.pop_back().unwrap()
    }

    /// Looks up a name starting at the current scope
    /// Returns ALL matches so that the caller can determine which definition is
    /// the correct one
    /// Definitions are returned in order from latest definition to oldest
    /// Always use the first definition that matches the type you are looking for
    pub fn lookup(&self, name: &Identifier) -> Vec<&ScopeItem> {
        self.stack.iter().rev().map(|sc| sc.get(name)).fold(Vec::new(), |mut acc, r| match r {
            Some(def) => {
                acc.push(def);
                acc
            },
            None => acc,
        })
    }

    /// Declares a name with the given type, allocates enough space for that type
    /// The name is declared in the "current" scope which is at the top of the stack
    /// Returns the allocated memory block
    pub fn declare(&mut self, name: String, typ: &ItemType) -> MemoryBlock {
        let mem = self.allocate(typ);
        // It's OK to overwrite existing names because we support rebinding
        if let Some(scope) = self.stack.back_mut() {
            scope.insert(name, ScopeItem {
                type_def: typ.clone(),
                memory: mem,
            });
        }
        else {
            panic!("Attempt to declare name despite having no current scope");
        }

        mem
    }

    /// Declares a built in function with the given name and type definition
    /// The name is declared in the "current" scope which is at the top of the stack
    /// Returns the allocated memory block
    fn declare_builtin_function<F: 'static>(&mut self, name: String, func_type: FunctionTypeDef, f: F) -> MemoryBlock
        where F: Fn(FuncArgs, ScopeStack) -> Vec<Operation> {

        self.declare(
            name,
            &ItemType::BuiltInFunction {
                type_def: func_type,
                operations: Rc::new(f),
            }
        )
    }

    /// Allocate a memory block that is large enough for the given type
    /// Does not associate memory block with a name which means it cannot be looked up later
    /// Returns the allocated memory block
    pub fn allocate(&mut self, typ: &ItemType) -> MemoryBlock {
        let size = typ.required_size(self);
        self.allocator.allocate(size)
    }
}

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

    use parser::Identifier;
    use operations::item_type::ItemType;

    #[test]
    fn multiple_definitions() {
        let mut scope = ScopeStack::new();
        assert_eq!(scope.lookup(&Identifier::from("foo")).len(), 0);

        scope.declare("foo".to_owned(), &ItemType::Primitive(1));
        assert_eq!(scope.lookup(&Identifier::from("foo")).len(), 1);

        // Declaring the same name in the same scope should overwrite the
        // definition
        scope.declare("foo".to_owned(), &ItemType::Primitive(1));
        assert_eq!(scope.lookup(&Identifier::from("foo")).len(), 1);

        scope.push_scope();
        // Declaring foo in another scope should add a definition
        scope.declare("foo".to_owned(), &ItemType::Primitive(1));
        assert_eq!(scope.lookup(&Identifier::from("foo")).len(), 2);

        // Declaring the same name in the same scope should overwrite the
        // definition
        scope.declare("foo".to_owned(), &ItemType::Primitive(1));
        assert_eq!(scope.lookup(&Identifier::from("foo")).len(), 2);
    }
}
<commit_msg>Replacing use of String with Identifier<commit_after>use std::rc::Rc;
use std::collections::{VecDeque, HashMap};

use parser::Identifier;
use memory::{StaticAllocator, MemoryBlock};

use super::operation::Operation;
use super::item_type::{ItemType, FunctionTypeDef, FuncArgs};

/// Represents a single item in a scope
pub struct ScopeItem {
    pub type_def: ItemType,
    pub memory: MemoryBlock,
}

/// Represents a single level of scope
pub type Scope = HashMap<Identifier, ScopeItem>;

pub struct ScopeStack {
    stack: VecDeque<Scope>,
    allocator: StaticAllocator,
}

impl ScopeStack {
    pub fn new() -> ScopeStack {
        ScopeStack {
            stack: {
                let mut queue = VecDeque::new();
                queue.push_back(Scope::new());
                queue
            },
            allocator: StaticAllocator::new(),
        }
    }

    /// Pushes a new level of scope onto the stack
    /// This scope will become the current scope
    pub fn push_scope(&mut self) {
        self.stack.push_back(Scope::new());
    }

    /// Removes and returns the top level scope (current scope)
    ///
    /// # Panics
    /// Panics if there is no scope in the stack
    pub fn pop_scope(&mut self) -> Scope {
        self.stack.pop_back().unwrap()
    }

    /// Looks up a name starting at the current scope
    /// Returns ALL matches so that the caller can determine which definition is
    /// the correct one
    /// Definitions are returned in order from latest definition to oldest
    /// Always use the first definition that matches the type you are looking for
    pub fn lookup(&self, name: &Identifier) -> Vec<&ScopeItem> {
        self.stack.iter().rev().map(|sc| sc.get(name)).fold(Vec::new(), |mut acc, r| match r {
            Some(def) => {
                acc.push(def);
                acc
            },
            None => acc,
        })
    }

    /// Declares a name with the given type, allocates enough space for that type
    /// The name is declared in the "current" scope which is at the top of the stack
    /// Returns the allocated memory block
    pub fn declare(&mut self, name: Identifier, typ: &ItemType) -> MemoryBlock {
        let mem = self.allocate(typ);
        // It's OK to overwrite existing names because we support rebinding
        if let Some(scope) = self.stack.back_mut() {
            scope.insert(name, ScopeItem {
                type_def: typ.clone(),
                memory: mem,
            });
        }
        else {
            panic!("Attempt to declare name despite having no current scope");
        }

        mem
    }

    /// Declares a built in function with the given name and type definition
    /// The name is declared in the "current" scope which is at the top of the stack
    /// Returns the allocated memory block
    fn declare_builtin_function<F: 'static>(&mut self, name: Identifier, func_type: FunctionTypeDef, f: F) -> MemoryBlock
        where F: Fn(FuncArgs, ScopeStack) -> Vec<Operation> {

        self.declare(
            name,
            &ItemType::BuiltInFunction {
                type_def: func_type,
                operations: Rc::new(f),
            }
        )
    }

    /// Allocate a memory block that is large enough for the given type
    /// Does not associate memory block with a name which means it cannot be looked up later
    /// Returns the allocated memory block
    pub fn allocate(&mut self, typ: &ItemType) -> MemoryBlock {
        let size = typ.required_size(self);
        self.allocator.allocate(size)
    }
}

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

    use parser::Identifier;
    use operations::item_type::ItemType;

    #[test]
    fn multiple_definitions() {
        let mut scope = ScopeStack::new();
        assert_eq!(scope.lookup(&Identifier::from("foo")).len(), 0);

        scope.declare(Identifier::from("foo"), &ItemType::Primitive(1));
        assert_eq!(scope.lookup(&Identifier::from("foo")).len(), 1);

        // Declaring the same name in the same scope should overwrite the
        // definition
        scope.declare(Identifier::from("foo"), &ItemType::Primitive(1));
        assert_eq!(scope.lookup(&Identifier::from("foo")).len(), 1);

        scope.push_scope();
        // Declaring foo in another scope should add a definition
        scope.declare(Identifier::from("foo"), &ItemType::Primitive(1));
        assert_eq!(scope.lookup(&Identifier::from("foo")).len(), 2);

        // Declaring the same name in the same scope should overwrite the
        // definition
        scope.declare(Identifier::from("foo"), &ItemType::Primitive(1));
        assert_eq!(scope.lookup(&Identifier::from("foo")).len(), 2);
    }
}
<|endoftext|>


<commit_before>use super::{Chunk, ChunkIndex};

/// A type that can load a game world, specifically single chunks of it. This
/// could mean loading a saved world from a file, generating a world
/// procedurally or loading a world from a server.
pub trait Provider {
    /// Attempt to load a chunk from the world. This may fail (e.g. when
    /// loading from a file and the chunk is not yet saved in the file).
    ///
    /// The given position is not a world position, but a chunk index. See the
    /// documentation of `ChunkIndex` for more information.
    ///
    /// # Warning
    ///
    /// This function may take some time to complete! To check whether a chunk
    /// can be loaded at all, prefer `is_chunk_loadable()`.
    fn load_chunk(&self, pos: ChunkIndex) -> Option<Chunk>;

    /// Determines whether or not the chunk at the given position can be
    /// loaded. This function is expected to return quickly.
    fn is_chunk_loadable(&self, pos: ChunkIndex) -> bool;
}

/// A dummy provider that always fails to provide a chunk.
#[derive(Clone, Copy, Debug)]
pub struct NullProvider;

impl Provider for NullProvider {
    fn load_chunk(&self, _: ChunkIndex) -> Option<Chunk> {
        None
    }

    fn is_chunk_loadable(&self, _: ChunkIndex) -> bool {
        false
    }
}
<commit_msg>add FallbackProvider<commit_after>use super::{Chunk, ChunkIndex};

/// A type that can load a game world, specifically single chunks of it. This
/// could mean loading a saved world from a file, generating a world
/// procedurally or loading a world from a server.
pub trait Provider {
    /// Attempt to load a chunk from the world. This may fail (e.g. when
    /// loading from a file and the chunk is not yet saved in the file).
    ///
    /// The given position is not a world position, but a chunk index. See the
    /// documentation of `ChunkIndex` for more information.
    ///
    /// # Warning
    ///
    /// This function may take some time to complete! To check whether a chunk
    /// can be loaded at all, prefer `is_chunk_loadable()`.
    fn load_chunk(&self, pos: ChunkIndex) -> Option<Chunk>;

    /// Determines whether or not the chunk at the given position can be
    /// loaded. This function is expected to return quickly.
    fn is_chunk_loadable(&self, pos: ChunkIndex) -> bool;
}

/// A dummy provider that always fails to provide a chunk.
#[derive(Clone, Copy, Debug)]
pub struct NullProvider;

impl Provider for NullProvider {
    fn load_chunk(&self, _: ChunkIndex) -> Option<Chunk> {
        None
    }

    fn is_chunk_loadable(&self, _: ChunkIndex) -> bool {
        false
    }
}

/// A fallback provider that holds two chunk providers with one beeing primary
/// and one fallback. If the chunk load from the primary fails the fallback
/// is being called.
#[derive(Clone, Debug, Copy)]
pub struct FallbackProvider<P, F> {
    primary: P,
    fallback: F,
}

impl<P: Provider, F: Provider> Provider for FallbackProvider<P, F> {
    fn load_chunk(&self, pos: ChunkIndex) -> Option<Chunk> {
        if self.primary.is_chunk_loadable(pos) {
            self.primary.load_chunk(pos)
        } else if self.fallback.is_chunk_loadable(pos) {
            self.fallback.load_chunk(pos)
        } else {
            NullProvider {}.load_chunk(pos)
        }
    }

    fn is_chunk_loadable(&self, pos: ChunkIndex) -> bool {
        self.primary.is_chunk_loadable(pos) || self.fallback.is_chunk_loadable(pos)
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 Nathan Sizemore <nathanrsizemore@gmail.com>
//
// This Source Code Form is subject to the
// terms of the Mozilla Public License, v.
// 2.0. If a copy of the MPL was not
// distributed with this file, You can
// obtain one at
// http://mozilla.org/MPL/2.0/.
//
// This Source Code Form is "Incompatible
// With Secondary Licenses", as defined by
// the Mozilla Public License, v. 2.0.

use std::thread;
use std::thread::JoinHandle;
use std::net::TcpStream;
use std::ops::DerefMut;
use std::os::unix::io::RawFd;
use std::collections::LinkedList;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::{
    channel,
    Sender,
    Receiver,
    TryRecvError
};

use super::types::*;
use super::epoll;
use super::epoll::util::*;
use super::epoll::EpollEvent;
use super::socket::Socket;
use super::simple_stream::nbetstream::NbetStream;

#[allow(dead_code)]
pub struct EventLoop {
    /// Handle to event loop process
    prox: JoinHandle<()>,
    /// Sender<T> to proc
    prox_tx: Sender<TcpStream>
}

impl EventLoop {

    /// Returns a new EventLoop
    pub fn new(server_tx: Sender<EventTuple>) -> EventLoop {
        let (tx, rx): (Sender<TcpStream>, Receiver<TcpStream>) = channel();
        let prox = thread::Builder::new()
            .name("EventLoop".to_string())
            .spawn(move || {
                EventLoop::start(rx, server_tx);
            }).unwrap();

        EventLoop {
            prox: prox,
            prox_tx: tx
        }
    }

    /// Returns a clone of this EventLoop's Sender<TcpStream> channel
    pub fn sender(&self) -> Sender<TcpStream> {
        self.prox_tx.clone()
    }

    /// Main event loop
    fn start(rx: Receiver<TcpStream>, uspace_tx: Sender<EventTuple>) {
        // Master socket list
        let sockets = Arc::new(Mutex::new(LinkedList::<Socket>::new()));

        // Our error handler for this thread and it's children
        let (err_tx, err_rx): (Sender<()>, Receiver<()>) = channel();

        // Create an epoll instance
        let result = epoll::create1(0);
        if result.is_err() {
            let err = result.unwrap_err();
            panic!("Unable to create epoll instance: {}", err)
        }
        let epoll_instance = result.unwrap();

        // Start the epoll thread
        let c_sockets = sockets.clone();
        let c_epoll_instance = epoll_instance.clone();
        let epoll_prox = thread::Builder::new()
            .name("EpollLoop".to_string())
            .spawn(move || {
                EventLoop::epoll_loop(uspace_tx, c_sockets, c_epoll_instance, err_rx);
            }).unwrap();

        for new_stream in rx.iter() {
            match NbetStream::new(new_stream) {
                Ok(s_stream) => {
                    // Add to master list
                    let socket = Socket::new(s_stream);

                    // TODO - Replace with recoverable version once into_inner() is stable
                    // Unfortunately, this is the only stable way to use mutexes at the moment
                    // Hopefully recovering from poisoning will be in 1.2
                    // let mut s_guard = match sockets.lock() {
                    //     Ok(guard) => guard,
                    //     Err(poisoned) => poisoned.into_inner()
                    // };
                    let mut s_guard = sockets.lock().unwrap();
                    let s_list = s_guard.deref_mut();
                    let s_fd = socket.raw_fd();
                    s_list.push_back(socket);

                    // Add to epoll
                    let event = Box::new(EpollEvent {
                        data: s_fd as u64,
                        events: (event_type::EPOLLIN | event_type::EPOLLET)
                    });
                    match epoll::ctl(epoll_instance, ctl_op::ADD, s_fd, event) {
                        Ok(()) => println!("New socket added to epoll list"),
                        Err(e) => println!("Epoll CtrlError during add: {}", e)
                    };
                }
                Err(e) => {
                    // TODO - write error to log file
                    println!("Error: {}", e);
                }
            };
        }

        // If we get here, shit is real bad. It means we have lost our
        // channel to the outside world.
        // Kill off event loop, so unwinding can begin
        println!("Rust.EventLoop.start - thread finished");
        let _ = err_tx.send(());
    }

    /// Calls epoll_wait forever waiting for events to be fired up from kernel
    fn epoll_loop(uspace_tx: Sender<EventTuple>,
                  sockets: SocketList,
                  epoll_instance: RawFd,
                  err_rx: Receiver<()>) {

        // This is the maximum number of events we want to be notified of at one time
        let mut events = Vec::<EpollEvent>::with_capacity(100);
        unsafe { events.set_len(100); }

        loop {
            // Wait for epoll events
            match epoll::wait(epoll_instance, &mut events[..], -1) {
                Ok(num_events) => {
                    println!("{} epoll event(s) received", num_events);
                    for x in 0..num_events {
                        let tx_clone = uspace_tx.clone();
                        let s_clone = sockets.clone();
                        let epfd_clone = epoll_instance.clone();

                        EventLoop::handle_epoll_event(epfd_clone,
                            &events[x as usize], s_clone, tx_clone);
                    }
                }
                Err(e) => {
                    panic!("Error on epoll::wait(): {}", e)
                }
            }

            // If we receive anything on this end or lose communication, we need to halt,
            // because we have no where to send up events, our "user space" channel is
            // gone
            match err_rx.try_recv() {
                Ok(_) => {
                    println!("Error, terminating epoll_loop");
                    break;
                }
                Err(e) => {
                    match e {
                        TryRecvError::Empty => {}
                        _ => {
                            println!("Error, terminating epoll_loo");
                            break;
                        }
                    }
                }
            }
        }
        println!("Rust.EventLoop.epoll_loop - thread finished");
    }

    /// Processes a read on the socket that is ready for reading
    ///
    /// An epoll event is passed to this function, with the fd that is ready to be read
    /// A traversal through the list of sockets is then performed in order to locate the
    /// NbetStream instance that is wrapping that file descriptor.
    /// After a read is performed on that socket, it's data will be passed back to the
    /// "user-space" section of the Server to process the payload however it needs to.
    ///
    /// TODO - Create a faster way to gain a safe reference to the NbetStream wrapping
    /// the fd instead of an O(n) lookup for every event. Currently lookup time is
    /// O(n) * MAX_EPOLL_EVENTS, where MAX_EPOLL_EVENTS is user defined in this function's
    /// caller.
    fn handle_epoll_event(epoll_instance: RawFd,
                          event: &EpollEvent,
                          sockets: SocketList,
                          uspace_tx: Sender<EventTuple>) {

        println!("Rust.EventLoop.handle_epoll_event");

        // List of socket id's that produced an Err on read attempt
        // Cannot do it within the match block because the list will need
        // access to the mutex, while this scope has the mutex, which will result
        // in a spinlock that will spin forever. And, that's a trip to bummer town
        let mut errd_socket_ids = Vec::<u32>::new();

        // The fd we are traversing the list for
        let fd = event.data;

        // We need a handle before the list gets locked and used
        let s_list_clone = sockets.clone();

        // TODO - Replace with recoverable version once into_inner() is stable
        // Unfortunately, this is the only stable way to use mutexes at the moment
        // Hopefully recovering from poisoning will be in 1.2
        // let mut s_guard = match sockets.lock() {
        //     Ok(guard) => guard,
        //     Err(poisoned) => poisoned.into_inner()
        // };
        let mut s_guard = sockets.lock().unwrap();
        let s_list = s_guard.deref_mut();
        for socket in s_list.iter_mut() {
            if socket.raw_fd() as u64 == fd {
                // We've found the socket for the event passed from epoll
                // Lets attempt to read from it
                match socket.read() {
                    Ok(()) => {
                        println!("Rust.EventLoop.handle_epoll_event.socket.read.Ok()");
                        for msg in socket.buffer().iter() {
                            let msg_for_debug = msg.clone();
                            match String::from_utf8(msg_for_debug) {
                                Ok(msg_str) => {
                                    println!("Rust.EventLoop.handle_epoll_event.socket.read.ok.msg_as_string: {}", msg_str);
                                }
                                Err(e) => {
                                    println!("Rust.EventLoop.handle_epoll_event.socket.read.ok.msg_as_string.Err: {}", e);
                                }
                            };

                            let list_handle = s_list_clone.clone();
                            let socket_clone = socket.clone();
                            let msg_clone = msg.clone();
                            let _ = uspace_tx.send((list_handle, socket_clone, msg_clone));
                        }
                    }
                    Err(e) => {
                        println!("Rust.EventLoop.handle_epoll_event.socket.read.Err(e): {}", e);
                        // We really don't care what happened, it all results in the same
                        // outcome - remove the socket from system...
                        errd_socket_ids.push(socket.id());
                        let s_clone = socket.clone();
                        let epfd_clone = epoll_instance.clone();
                        EventLoop::remove_socket_from_epoll(s_clone, epfd_clone);
                    }
                }
            }
        }

        // Remove any errd sockets from the master list of sockets
        EventLoop::remove_socket_from_list(errd_socket_ids, list_clone);
    }

    /// Removes socket from the epoll watch list
    fn remove_socket_from_epoll(socket: Socket, epoll_instance: RawFd) {
        println!("remove_socket_from_epoll");

        // In kernel versions before 2.6.9, the EPOLL_CTL_DEL operation required
        // a non-null pointer in event, even though this argument is ignored.
        // Since Linux 2.6.9, event can be specified as NULL when using
        // EPOLL_CTL_DEL.  Applications that need to be portable to kernels
        // before 2.6.9 should specify a non-null pointer in event.
        let event = Box::new(EpollEvent {
            data: 0 as u64,
            events: 0 as u32
        });
        let s_fd = socket.raw_fd();

        // Depending on how fd are duplicated with .clone(), this may fail
        // If the failure case is CtlError::ENOENT, we do not care, because
        // epoll will clean the up the descriptor after they are all dropped from
        // program memory
        match epoll::ctl(epoll_instance, ctl_op::DEL, s_fd, event) {
            Ok(()) => println!("Socket removed from epoll watch list"),
            Err(e) => {
                match e {
                    CtlError::ENOENT => {
                        println!("Fd not found in epoll, will remove when fd is syscall closed");
                    }
                    _ => println!("Epoll CtrlError during del: {}", e)
                }
            }
        };
    }

    /// Removes socket from master list
    fn remove_socket_from_list(socket_ids: Vec<u32>, sockets: SocketList) {
        println!("remove_socket_from_list");

        // TODO - Replace with recoverable version once into_inner() is stable
        // Unfortunately, this is the only stable way to use mutexes at the moment
        // Hopefully recovering from poisoning will be in 1.2
        // let mut s_guard = match sockets.lock() {
        //     Ok(guard) => guard,
        //     Err(poisoned) => poisoned.into_inner()
        // };
        let mut s_guard = sockets.lock().unwrap();
        let s_list = s_guard.deref_mut();

        for socket_id in socket_ids.iter() {
            let mut socket_found = false;
            let mut index: usize = 1;
            for socket in s_list.iter() {
                if socket.id() == socket_id {
                    socket_found = true;
                    break;
                }
                index += 1;
            }

            if !socket_found {
                println!("Socket not found in list...?");
                return;
            }

            if index == 1 {
                s_list.pop_front();
            } else {
                let mut split = s_list.split_off(index - 1);
                split.pop_front();
                s_list.append(&mut split);
            }

            println!("Socket removed sucessfully");
        }
    }
}
<commit_msg>rustc is not picking up a lot of things...?<commit_after>// Copyright 2015 Nathan Sizemore <nathanrsizemore@gmail.com>
//
// This Source Code Form is subject to the
// terms of the Mozilla Public License, v.
// 2.0. If a copy of the MPL was not
// distributed with this file, You can
// obtain one at
// http://mozilla.org/MPL/2.0/.
//
// This Source Code Form is "Incompatible
// With Secondary Licenses", as defined by
// the Mozilla Public License, v. 2.0.

use std::thread;
use std::thread::JoinHandle;
use std::net::TcpStream;
use std::ops::DerefMut;
use std::os::unix::io::RawFd;
use std::collections::LinkedList;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::{
    channel,
    Sender,
    Receiver,
    TryRecvError
};

use super::types::*;
use super::epoll;
use super::epoll::util::*;
use super::epoll::EpollEvent;
use super::socket::Socket;
use super::simple_stream::nbetstream::NbetStream;

#[allow(dead_code)]
pub struct EventLoop {
    /// Handle to event loop process
    prox: JoinHandle<()>,
    /// Sender<T> to proc
    prox_tx: Sender<TcpStream>
}

impl EventLoop {

    /// Returns a new EventLoop
    pub fn new(server_tx: Sender<EventTuple>) -> EventLoop {
        let (tx, rx): (Sender<TcpStream>, Receiver<TcpStream>) = channel();
        let prox = thread::Builder::new()
            .name("EventLoop".to_string())
            .spawn(move || {
                EventLoop::start(rx, server_tx);
            }).unwrap();

        EventLoop {
            prox: prox,
            prox_tx: tx
        }
    }

    /// Returns a clone of this EventLoop's Sender<TcpStream> channel
    pub fn sender(&self) -> Sender<TcpStream> {
        self.prox_tx.clone()
    }

    /// Main event loop
    fn start(rx: Receiver<TcpStream>, uspace_tx: Sender<EventTuple>) {
        // Master socket list
        let sockets = Arc::new(Mutex::new(LinkedList::<Socket>::new()));

        // Our error handler for this thread and it's children
        let (err_tx, err_rx): (Sender<()>, Receiver<()>) = channel();

        // Create an epoll instance
        let result = epoll::create1(0);
        if result.is_err() {
            let err = result.unwrap_err();
            panic!("Unable to create epoll instance: {}", err)
        }
        let epoll_instance = result.unwrap();

        // Start the epoll thread
        let c_sockets = sockets.clone();
        let c_epoll_instance = epoll_instance.clone();
        let epoll_prox = thread::Builder::new()
            .name("EpollLoop".to_string())
            .spawn(move || {
                EventLoop::epoll_loop(uspace_tx, c_sockets, c_epoll_instance, err_rx);
            }).unwrap();

        for new_stream in rx.iter() {
            match NbetStream::new(new_stream) {
                Ok(s_stream) => {
                    // Add to master list
                    let socket = Socket::new(s_stream);

                    // TODO - Replace with recoverable version once into_inner() is stable
                    // Unfortunately, this is the only stable way to use mutexes at the moment
                    // Hopefully recovering from poisoning will be in 1.2
                    // let mut s_guard = match sockets.lock() {
                    //     Ok(guard) => guard,
                    //     Err(poisoned) => poisoned.into_inner()
                    // };
                    let mut s_guard = sockets.lock().unwrap();
                    let s_list = s_guard.deref_mut();
                    let s_fd = socket.raw_fd();
                    s_list.push_back(socket);

                    // Add to epoll
                    let event = Box::new(EpollEvent {
                        data: s_fd as u64,
                        events: (event_type::EPOLLIN | event_type::EPOLLET)
                    });
                    match epoll::ctl(epoll_instance, ctl_op::ADD, s_fd, event) {
                        Ok(()) => println!("New socket added to epoll list"),
                        Err(e) => println!("Epoll CtrlError during add: {}", e)
                    };
                }
                Err(e) => {
                    // TODO - write error to log file
                    println!("Error: {}", e);
                }
            };
        }

        // If we get here, shit is real bad. It means we have lost our
        // channel to the outside world.
        // Kill off event loop, so unwinding can begin
        println!("Rust.EventLoop.start - thread finished");
        let _ = err_tx.send(());
    }

    /// Calls epoll_wait forever waiting for events to be fired up from kernel
    fn epoll_loop(uspace_tx: Sender<EventTuple>,
                  sockets: SocketList,
                  epoll_instance: RawFd,
                  err_rx: Receiver<()>) {

        // This is the maximum number of events we want to be notified of at one time
        let mut events = Vec::<EpollEvent>::with_capacity(100);
        unsafe { events.set_len(100); }

        loop {
            // Wait for epoll events
            match epoll::wait(epoll_instance, &mut events[..], -1) {
                Ok(num_events) => {
                    println!("{} epoll event(s) received", num_events);
                    for x in 0..num_events {
                        let tx_clone = uspace_tx.clone();
                        let s_clone = sockets.clone();
                        let epfd_clone = epoll_instance.clone();

                        EventLoop::handle_epoll_event(epfd_clone,
                            &events[x as usize], s_clone, tx_clone);
                    }
                }
                Err(e) => {
                    panic!("Error on epoll::wait(): {}", e)
                }
            }

            // If we receive anything on this end or lose communication, we need to halt,
            // because we have no where to send up events, our "user space" channel is
            // gone
            match err_rx.try_recv() {
                Ok(_) => {
                    println!("Error, terminating epoll_loop");
                    break;
                }
                Err(e) => {
                    match e {
                        TryRecvError::Empty => {}
                        _ => {
                            println!("Error, terminating epoll_loo");
                            break;
                        }
                    }
                }
            }
        }
        println!("Rust.EventLoop.epoll_loop - thread finished");
    }

    /// Processes a read on the socket that is ready for reading
    ///
    /// An epoll event is passed to this function, with the fd that is ready to be read
    /// A traversal through the list of sockets is then performed in order to locate the
    /// NbetStream instance that is wrapping that file descriptor.
    /// After a read is performed on that socket, it's data will be passed back to the
    /// "user-space" section of the Server to process the payload however it needs to.
    ///
    /// TODO - Create a faster way to gain a safe reference to the NbetStream wrapping
    /// the fd instead of an O(n) lookup for every event. Currently lookup time is
    /// O(n) * MAX_EPOLL_EVENTS, where MAX_EPOLL_EVENTS is user defined in this function's
    /// caller.
    fn handle_epoll_event(epoll_instance: RawFd,
                          event: &EpollEvent,
                          sockets: SocketList,
                          uspace_tx: Sender<EventTuple>) {

        println!("Rust.EventLoop.handle_epoll_event");

        // List of socket id's that produced an Err on read attempt
        // Cannot do it within the match block because the list will need
        // access to the mutex, while this scope has the mutex, which will result
        // in a spinlock that will spin forever. And, that's a trip to bummer town
        let mut errd_socket_ids = Vec::<u32>::new();

        // The fd we are traversing the list for
        let fd = event.data;

        // We need a handle before the list gets locked and used
        let s_list_clone = sockets.clone();

        // TODO - Replace with recoverable version once into_inner() is stable
        // Unfortunately, this is the only stable way to use mutexes at the moment
        // Hopefully recovering from poisoning will be in 1.2
        // let mut s_guard = match sockets.lock() {
        //     Ok(guard) => guard,
        //     Err(poisoned) => poisoned.into_inner()
        // };
        let mut s_guard = sockets.lock().unwrap();
        let s_list = s_guard.deref_mut();
        for socket in s_list.iter_mut() {
            if socket.raw_fd() as u64 == fd {
                // We've found the socket for the event passed from epoll
                // Lets attempt to read from it
                match socket.read() {
                    Ok(()) => {
                        println!("Rust.EventLoop.handle_epoll_event.socket.read.Ok()");
                        for msg in socket.buffer().iter() {
                            let msg_for_debug = msg.clone();
                            match String::from_utf8(msg_for_debug) {
                                Ok(msg_str) => {
                                    println!("Rust.EventLoop.handle_epoll_event.socket.read.ok.msg_as_string: {}", msg_str);
                                }
                                Err(e) => {
                                    println!("Rust.EventLoop.handle_epoll_event.socket.read.ok.msg_as_string.Err: {}", e);
                                }
                            };

                            let list_handle = s_list_clone.clone();
                            let socket_clone = socket.clone();
                            let msg_clone = msg.clone();
                            let _ = uspace_tx.send((list_handle, socket_clone, msg_clone));
                        }
                    }
                    Err(e) => {
                        println!("Rust.EventLoop.handle_epoll_event.socket.read.Err(e): {}", e);
                        // We really don't care what happened, it all results in the same
                        // outcome - remove the socket from system...
                        errd_socket_ids.push(socket.id());
                        let s_clone = socket.clone();
                        let epfd_clone = epoll_instance.clone();
                        EventLoop::remove_socket_from_epoll(s_clone, epfd_clone);
                    }
                }
            }
        }

        // Remove any errd sockets from the master list of sockets
        EventLoop::remove_socket_from_list(errd_socket_ids, s_list_clone);
    }

    /// Removes socket from the epoll watch list
    fn remove_socket_from_epoll(socket: Socket, epoll_instance: RawFd) {
        println!("remove_socket_from_epoll");

        // In kernel versions before 2.6.9, the EPOLL_CTL_DEL operation required
        // a non-null pointer in event, even though this argument is ignored.
        // Since Linux 2.6.9, event can be specified as NULL when using
        // EPOLL_CTL_DEL.  Applications that need to be portable to kernels
        // before 2.6.9 should specify a non-null pointer in event.
        let event = Box::new(EpollEvent {
            data: 0 as u64,
            events: 0 as u32
        });
        let s_fd = socket.raw_fd();

        // Depending on how fd are duplicated with .clone(), this may fail
        // If the failure case is CtlError::ENOENT, we do not care, because
        // epoll will clean the up the descriptor after they are all dropped from
        // program memory
        match epoll::ctl(epoll_instance, ctl_op::DEL, s_fd, event) {
            Ok(()) => println!("Socket removed from epoll watch list"),
            Err(e) => {
                match e {
                    CtlError::ENOENT => {
                        println!("Fd not found in epoll, will remove when fd is syscall closed");
                    }
                    _ => println!("Epoll CtrlError during del: {}", e)
                }
            }
        };
    }

    /// Removes socket from master list
    fn remove_socket_from_list(socket_ids: Vec<u32>, sockets: SocketList) {
        println!("remove_socket_from_list");

        // TODO - Replace with recoverable version once into_inner() is stable
        // Unfortunately, this is the only stable way to use mutexes at the moment
        // Hopefully recovering from poisoning will be in 1.2
        // let mut s_guard = match sockets.lock() {
        //     Ok(guard) => guard,
        //     Err(poisoned) => poisoned.into_inner()
        // };
        let mut s_guard = sockets.lock().unwrap();
        let s_list = s_guard.deref_mut();

        for socket_id in socket_ids.iter() {
            let mut socket_found = false;
            let mut index: usize = 1;
            for socket in s_list.iter() {
                if socket.id() == socket_id {
                    socket_found = true;
                    break;
                }
                index += 1;
            }

            if !socket_found {
                println!("Socket not found in list...?");
                return;
            }

            if index == 1 {
                s_list.pop_front();
            } else {
                let mut split = s_list.split_off(index - 1);
                split.pop_front();
                s_list.append(&mut split);
            }

            println!("Socket removed sucessfully");
        }
    }
}
<|endoftext|>