<commit_before>use server::transactions::TxnId;
use server::transactions::*;
use ram::cell::{Cell, ReadError, WriteError};
use ram::types::{Id};
use std::sync::Arc;
use std::io;

use bifrost::rpc::RPCError;

#[derive(Debug)]
pub enum TxnError {
    CannotFindAServer,
    IoError(io::Error),
    CannotBegin,
    NotRealizable,
    TooManyRetry,
    InternalError,
    Aborted,
    RPCError(RPCError),
    ManagerError(TMError),
    ReadError(ReadError),
    WriteError(WriteError),
    PrepareError(TMPrepareResult),
    CommitError(EndResult),
    AbortError(AbortResult),
}

pub struct Transaction {
    pub tid: TxnId,
    pub state: TxnState,
    pub client: Arc<manager::SyncServiceClient>,
    pub changes: u32,
}

impl Transaction {

    pub fn read(&mut self, id: &Id) -> Result<Option<Cell>, TxnError> {
        self.changes += 1;
        match self.client.read(&self.tid, id) {
            Ok(Ok(TxnExecResult::Accepted(cell))) => Ok(Some(cell)),
            Ok(Ok(TxnExecResult::Rejected)) => Err(TxnError::NotRealizable),
            Ok(Ok(TxnExecResult::Error(ReadError::CellDoesNotExisted))) => Ok(None),
            Ok(Ok(_)) => Err(TxnError::InternalError),
            Ok(Err(tme)) => Err(TxnError::ManagerError(tme)),
            Ok(Ok(TxnExecResult::Error(re))) => Err(TxnError::ReadError(re)),
            Err(e) => Err(TxnError::RPCError(e))
        }
    }
    pub fn write(&mut self, cell: &Cell) -> Result<(), TxnError> {
        self.changes += 1;
        match self.client.write(&self.tid, cell) {
            Ok(Ok(TxnExecResult::Accepted(()))) => Ok(()),
            Ok(Ok(TxnExecResult::Rejected)) => Err(TxnError::NotRealizable),
            Ok(Ok(TxnExecResult::Error(we))) => Err(TxnError::WriteError(we)),
            Ok(Ok(_)) => Err(TxnError::InternalError),
            Ok(Err(tme)) => Err(TxnError::ManagerError(tme)),
            Err(e) => Err(TxnError::RPCError(e))
        }
    }
    pub fn update(&mut self, cell: &Cell) -> Result<(), TxnError> {
        self.changes += 1;
        match self.client.update(&self.tid, cell) {
            Ok(Ok(TxnExecResult::Accepted(()))) => Ok(()),
            Ok(Ok(TxnExecResult::Rejected)) => Err(TxnError::NotRealizable),
            Ok(Ok(TxnExecResult::Error(we))) => Err(TxnError::WriteError(we)),
            Ok(Ok(_)) => Err(TxnError::InternalError),
            Ok(Err(tme)) => Err(TxnError::ManagerError(tme)),
            Err(e) => Err(TxnError::RPCError(e))
        }
    }
    pub fn remove(&mut self, id: &Id) -> Result<(), TxnError> {
        self.changes += 1;
        match self.client.remove(&self.tid, id) {
            Ok(Ok(TxnExecResult::Accepted(()))) => Ok(()),
            Ok(Ok(TxnExecResult::Rejected)) => Err(TxnError::NotRealizable),
            Ok(Ok(TxnExecResult::Error(we))) => Err(TxnError::WriteError(we)),
            Ok(Ok(_)) => Err(TxnError::InternalError),
            Ok(Err(tme)) => Err(TxnError::ManagerError(tme)),
            Err(e) => Err(TxnError::RPCError(e))
        }
    }

    pub fn prepare(&mut self) -> Result<(), TxnError> {
        self.state = TxnState::Prepared;
        match self.client.prepare(&self.tid) {
            Ok(Ok(TMPrepareResult::Success)) => return Ok(()),
            Ok(Ok(TMPrepareResult::DMPrepareError
                  (DMPrepareResult::NotRealizable))) =>
                Err(TxnError::NotRealizable),
            Ok(Ok(TMPrepareResult::DMCommitError(
                      DMCommitResult::CellChanged(_, _)))) =>
                Err(TxnError::NotRealizable),
            Ok(Ok(rpr)) => Err(TxnError::PrepareError(rpr)),
            Ok(Err(tme)) => Err(TxnError::ManagerError(tme)),
            Err(e) => Err(TxnError::RPCError(e))
        }
    }
    pub fn commit(&mut self) -> Result<(), TxnError> {
        self.state = TxnState::Committed;
        match self.client.commit(&self.tid) {
            Ok(Ok(EndResult::Success)) => return Ok(()),
            Ok(Ok(EndResult::SomeLocksNotReleased)) => return Ok(()),
            Ok(Ok(er)) => Err(TxnError::CommitError(er)),
            Ok(Err(tme)) => Err(TxnError::ManagerError(tme)),
            Err(e) => Err(TxnError::RPCError(e))
        }
    }
    pub fn abort(&mut self) -> Result<(), TxnError> {
        if self.state == TxnState::Aborted {return Ok(());}
        self.state = TxnState::Aborted;
        match self.client.abort(&self.tid) {
            Ok(Ok(AbortResult::Success(_))) => Err(TxnError::Aborted),
            Ok(Ok(ar)) => Err(TxnError::AbortError(ar)),
            Ok(Err(tme)) => Err(TxnError::ManagerError(tme)),
            Err(e) => Err(TxnError::RPCError(e))
        }
    }
}<commit_msg>transaction read selected in client<commit_after>use server::transactions::TxnId;
use server::transactions::*;
use ram::cell::{Cell, ReadError, WriteError};
use ram::types::{Id, Value};
use std::sync::Arc;
use std::io;

use bifrost::rpc::RPCError;

#[derive(Debug)]
pub enum TxnError {
    CannotFindAServer,
    IoError(io::Error),
    CannotBegin,
    NotRealizable,
    TooManyRetry,
    InternalError,
    Aborted,
    RPCError(RPCError),
    ManagerError(TMError),
    ReadError(ReadError),
    WriteError(WriteError),
    PrepareError(TMPrepareResult),
    CommitError(EndResult),
    AbortError(AbortResult),
}

pub struct Transaction {
    pub tid: TxnId,
    pub state: TxnState,
    pub client: Arc<manager::SyncServiceClient>,
    pub changes: u32,
}

impl Transaction {

    pub fn read(&mut self, id: &Id) -> Result<Option<Cell>, TxnError> {
        self.changes += 1;
        match self.client.read(&self.tid, id) {
            Ok(Ok(TxnExecResult::Accepted(cell))) => Ok(Some(cell)),
            Ok(Ok(TxnExecResult::Rejected)) => Err(TxnError::NotRealizable),
            Ok(Ok(TxnExecResult::Error(ReadError::CellDoesNotExisted))) => Ok(None),
            Ok(Ok(TxnExecResult::Error(re))) => Err(TxnError::ReadError(re)),
            Ok(Ok(_)) => Err(TxnError::InternalError),
            Ok(Err(tme)) => Err(TxnError::ManagerError(tme)),
            Err(e) => Err(TxnError::RPCError(e))
        }
    }
    pub fn read_selected(&mut self, id: &Id, fields: &Vec<u64>) -> Result<Option<Vec<Value>>, TxnError> {
        self.changes += 1;
        match self.client.read_selected(&self.tid, id, fields) {
            Ok(Ok(TxnExecResult::Accepted(fields))) => Ok(Some(fields)),
            Ok(Ok(TxnExecResult::Rejected)) => Err(TxnError::NotRealizable),
            Ok(Ok(TxnExecResult::Error(ReadError::CellDoesNotExisted))) => Ok(None),
            Ok(Ok(TxnExecResult::Error(re))) => Err(TxnError::ReadError(re)),
            Ok(Ok(_)) => Err(TxnError::InternalError),
            Ok(Err(tme)) => Err(TxnError::ManagerError(tme)),
            Err(e) => Err(TxnError::RPCError(e))
        }
    }
    pub fn write(&mut self, cell: &Cell) -> Result<(), TxnError> {
        self.changes += 1;
        match self.client.write(&self.tid, cell) {
            Ok(Ok(TxnExecResult::Accepted(()))) => Ok(()),
            Ok(Ok(TxnExecResult::Rejected)) => Err(TxnError::NotRealizable),
            Ok(Ok(TxnExecResult::Error(we))) => Err(TxnError::WriteError(we)),
            Ok(Ok(_)) => Err(TxnError::InternalError),
            Ok(Err(tme)) => Err(TxnError::ManagerError(tme)),
            Err(e) => Err(TxnError::RPCError(e))
        }
    }
    pub fn update(&mut self, cell: &Cell) -> Result<(), TxnError> {
        self.changes += 1;
        match self.client.update(&self.tid, cell) {
            Ok(Ok(TxnExecResult::Accepted(()))) => Ok(()),
            Ok(Ok(TxnExecResult::Rejected)) => Err(TxnError::NotRealizable),
            Ok(Ok(TxnExecResult::Error(we))) => Err(TxnError::WriteError(we)),
            Ok(Ok(_)) => Err(TxnError::InternalError),
            Ok(Err(tme)) => Err(TxnError::ManagerError(tme)),
            Err(e) => Err(TxnError::RPCError(e))
        }
    }
    pub fn remove(&mut self, id: &Id) -> Result<(), TxnError> {
        self.changes += 1;
        match self.client.remove(&self.tid, id) {
            Ok(Ok(TxnExecResult::Accepted(()))) => Ok(()),
            Ok(Ok(TxnExecResult::Rejected)) => Err(TxnError::NotRealizable),
            Ok(Ok(TxnExecResult::Error(we))) => Err(TxnError::WriteError(we)),
            Ok(Ok(_)) => Err(TxnError::InternalError),
            Ok(Err(tme)) => Err(TxnError::ManagerError(tme)),
            Err(e) => Err(TxnError::RPCError(e))
        }
    }

    pub fn prepare(&mut self) -> Result<(), TxnError> {
        self.state = TxnState::Prepared;
        match self.client.prepare(&self.tid) {
            Ok(Ok(TMPrepareResult::Success)) => return Ok(()),
            Ok(Ok(TMPrepareResult::DMPrepareError
                  (DMPrepareResult::NotRealizable))) =>
                Err(TxnError::NotRealizable),
            Ok(Ok(TMPrepareResult::DMCommitError(
                      DMCommitResult::CellChanged(_, _)))) =>
                Err(TxnError::NotRealizable),
            Ok(Ok(rpr)) => Err(TxnError::PrepareError(rpr)),
            Ok(Err(tme)) => Err(TxnError::ManagerError(tme)),
            Err(e) => Err(TxnError::RPCError(e))
        }
    }
    pub fn commit(&mut self) -> Result<(), TxnError> {
        self.state = TxnState::Committed;
        match self.client.commit(&self.tid) {
            Ok(Ok(EndResult::Success)) => return Ok(()),
            Ok(Ok(EndResult::SomeLocksNotReleased)) => return Ok(()),
            Ok(Ok(er)) => Err(TxnError::CommitError(er)),
            Ok(Err(tme)) => Err(TxnError::ManagerError(tme)),
            Err(e) => Err(TxnError::RPCError(e))
        }
    }
    pub fn abort(&mut self) -> Result<(), TxnError> {
        if self.state == TxnState::Aborted {return Ok(());}
        self.state = TxnState::Aborted;
        match self.client.abort(&self.tid) {
            Ok(Ok(AbortResult::Success(_))) => Err(TxnError::Aborted),
            Ok(Ok(ar)) => Err(TxnError::AbortError(ar)),
            Ok(Err(tme)) => Err(TxnError::ManagerError(tme)),
            Err(e) => Err(TxnError::RPCError(e))
        }
    }
}<|endoftext|>


<commit_before>//! `SourceBinder` should be the main entry point for getting info about source code.
//! It's main task is to map source syntax trees to hir-level IDs.
//!
//! It is intended to subsume `FromSource` and `SourceAnalyzer`.

use hir_def::{
    child_by_source::ChildBySource,
    dyn_map::DynMap,
    keys::{self, Key},
    resolver::{HasResolver, Resolver},
    ConstId, DefWithBodyId, EnumId, EnumVariantId, FunctionId, GenericDefId, ImplId, ModuleId,
    StaticId, StructFieldId, StructId, TraitId, TypeAliasId, UnionId, VariantId,
};
use hir_expand::{name::AsName, AstId, InFile, MacroDefId, MacroDefKind};
use ra_prof::profile;
use ra_syntax::{
    ast::{self, NameOwner},
    match_ast, AstNode, SyntaxNode, TextUnit,
};
use rustc_hash::FxHashMap;

use crate::{db::HirDatabase, Local, Module, SourceAnalyzer, TypeParam};
use ra_db::FileId;

pub struct SourceBinder<'a, DB> {
    pub db: &'a DB,
    child_by_source_cache: FxHashMap<ChildContainer, DynMap>,
}

impl<DB: HirDatabase> SourceBinder<'_, DB> {
    pub fn new(db: &DB) -> SourceBinder<DB> {
        SourceBinder { db, child_by_source_cache: FxHashMap::default() }
    }

    pub fn analyze(
        &mut self,
        src: InFile<&SyntaxNode>,
        offset: Option<TextUnit>,
    ) -> SourceAnalyzer {
        let _p = profile("SourceBinder::analyzer");
        let container = match self.find_container(src) {
            Some(it) => it,
            None => return SourceAnalyzer::new_for_resolver(Resolver::default(), src),
        };

        let resolver = match container {
            ChildContainer::DefWithBodyId(def) => {
                return SourceAnalyzer::new_for_body(self.db, def, src, offset)
            }
            ChildContainer::TraitId(it) => it.resolver(self.db),
            ChildContainer::ImplId(it) => it.resolver(self.db),
            ChildContainer::ModuleId(it) => it.resolver(self.db),
            ChildContainer::EnumId(it) => it.resolver(self.db),
            ChildContainer::VariantId(it) => it.resolver(self.db),
            ChildContainer::GenericDefId(it) => it.resolver(self.db),
        };
        SourceAnalyzer::new_for_resolver(resolver, src)
    }

    pub fn to_def<T: ToDef>(&mut self, src: InFile<T>) -> Option<T::Def> {
        T::to_def(self, src)
    }

    pub fn to_module_def(&mut self, file: FileId) -> Option<Module> {
        let _p = profile("SourceBinder::to_module_def");
        let (krate, local_id) = self.db.relevant_crates(file).iter().find_map(|&crate_id| {
            let crate_def_map = self.db.crate_def_map(crate_id);
            let local_id = crate_def_map.modules_for_file(file).next()?;
            Some((crate_id, local_id))
        })?;
        Some(Module { id: ModuleId { krate, local_id } })
    }

    fn to_id<T: ToId>(&mut self, src: InFile<T>) -> Option<T::ID> {
        T::to_id(self, src)
    }

    fn find_container(&mut self, src: InFile<&SyntaxNode>) -> Option<ChildContainer> {
        for container in src.cloned().ancestors_with_macros(self.db).skip(1) {
            let res: ChildContainer = match_ast! {
                match (container.value) {
                    ast::TraitDef(it) => {
                        let def: TraitId = self.to_id(container.with_value(it))?;
                        def.into()
                    },
                    ast::ImplBlock(it) => {
                        let def: ImplId = self.to_id(container.with_value(it))?;
                        def.into()
                    },
                    ast::FnDef(it) => {
                        let def: FunctionId = self.to_id(container.with_value(it))?;
                        DefWithBodyId::from(def).into()
                    },
                    ast::StaticDef(it) => {
                        let def: StaticId = self.to_id(container.with_value(it))?;
                        DefWithBodyId::from(def).into()
                    },
                    ast::ConstDef(it) => {
                        let def: ConstId = self.to_id(container.with_value(it))?;
                        DefWithBodyId::from(def).into()
                    },
                    ast::EnumDef(it) => {
                        let def: EnumId = self.to_id(container.with_value(it))?;
                        def.into()
                    },
                    ast::StructDef(it) => {
                        let def: StructId = self.to_id(container.with_value(it))?;
                        VariantId::from(def).into()
                    },
                    ast::UnionDef(it) => {
                        let def: UnionId = self.to_id(container.with_value(it))?;
                        VariantId::from(def).into()
                    },
                    // FIXME: handle out-of-line modules here
                    _ => { continue },
                }
            };
            return Some(res);
        }

        let c = self.to_module_def(src.file_id.original_file(self.db))?;
        Some(c.id.into())
    }

    fn child_by_source(&mut self, container: ChildContainer) -> &DynMap {
        let db = self.db;
        self.child_by_source_cache.entry(container).or_insert_with(|| match container {
            ChildContainer::DefWithBodyId(it) => it.child_by_source(db),
            ChildContainer::ModuleId(it) => it.child_by_source(db),
            ChildContainer::TraitId(it) => it.child_by_source(db),
            ChildContainer::ImplId(it) => it.child_by_source(db),
            ChildContainer::EnumId(it) => it.child_by_source(db),
            ChildContainer::VariantId(it) => it.child_by_source(db),
            ChildContainer::GenericDefId(it) => it.child_by_source(db),
        })
    }
}

pub trait ToId: Sized {
    type ID: Sized + Copy + 'static;
    fn to_id<DB: HirDatabase>(sb: &mut SourceBinder<'_, DB>, src: InFile<Self>)
        -> Option<Self::ID>;
}

pub trait ToDef: Sized + AstNode + 'static {
    type Def;
    fn to_def<DB: HirDatabase>(
        sb: &mut SourceBinder<'_, DB>,
        src: InFile<Self>,
    ) -> Option<Self::Def>;
}

macro_rules! to_def_impls {
    ($(($def:path, $ast:path)),* ,) => {$(
        impl ToDef for $ast {
            type Def = $def;
            fn to_def<DB: HirDatabase>(sb: &mut SourceBinder<'_, DB>, src: InFile<Self>)
                -> Option<Self::Def>
            { sb.to_id(src).map(Into::into) }
        }
    )*}
}

to_def_impls![
    (crate::Struct, ast::StructDef),
    (crate::Enum, ast::EnumDef),
    (crate::Union, ast::UnionDef),
    (crate::Trait, ast::TraitDef),
    (crate::ImplBlock, ast::ImplBlock),
    (crate::TypeAlias, ast::TypeAliasDef),
    (crate::Const, ast::ConstDef),
    (crate::Static, ast::StaticDef),
    (crate::Function, ast::FnDef),
    (crate::StructField, ast::RecordFieldDef),
    (crate::EnumVariant, ast::EnumVariant),
    (crate::MacroDef, ast::MacroCall), // this one is dubious, not all calls are macros
];

#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
enum ChildContainer {
    DefWithBodyId(DefWithBodyId),
    ModuleId(ModuleId),
    TraitId(TraitId),
    ImplId(ImplId),
    EnumId(EnumId),
    VariantId(VariantId),
    /// XXX: this might be the same def as, for example an `EnumId`. However,
    /// here the children generic parameters, and not, eg enum variants.
    GenericDefId(GenericDefId),
}
impl_froms! {
    ChildContainer:
    DefWithBodyId,
    ModuleId,
    TraitId,
    ImplId,
    EnumId,
    VariantId,
    GenericDefId
}

pub trait ToIdByKey: Sized + AstNode + 'static {
    type ID: Sized + Copy + 'static;
    const KEY: Key<Self, Self::ID>;
}

impl<T: ToIdByKey> ToId for T {
    type ID = <T as ToIdByKey>::ID;
    fn to_id<DB: HirDatabase>(
        sb: &mut SourceBinder<'_, DB>,
        src: InFile<Self>,
    ) -> Option<Self::ID> {
        let container = sb.find_container(src.as_ref().map(|it| it.syntax()))?;
        let db = sb.db;
        let dyn_map =
            &*sb.child_by_source_cache.entry(container).or_insert_with(|| match container {
                ChildContainer::DefWithBodyId(it) => it.child_by_source(db),
                ChildContainer::ModuleId(it) => it.child_by_source(db),
                ChildContainer::TraitId(it) => it.child_by_source(db),
                ChildContainer::ImplId(it) => it.child_by_source(db),
                ChildContainer::EnumId(it) => it.child_by_source(db),
                ChildContainer::VariantId(it) => it.child_by_source(db),
                ChildContainer::GenericDefId(it) => it.child_by_source(db),
            });
        dyn_map[T::KEY].get(&src).copied()
    }
}

macro_rules! to_id_key_impls {
    ($(($id:ident, $ast:path, $key:path)),* ,) => {$(
        impl ToIdByKey for $ast {
            type ID = $id;
            const KEY: Key<Self, Self::ID> = $key;
        }
    )*}
}

to_id_key_impls![
    (StructId, ast::StructDef, keys::STRUCT),
    (UnionId, ast::UnionDef, keys::UNION),
    (EnumId, ast::EnumDef, keys::ENUM),
    (TraitId, ast::TraitDef, keys::TRAIT),
    (FunctionId, ast::FnDef, keys::FUNCTION),
    (StaticId, ast::StaticDef, keys::STATIC),
    (ConstId, ast::ConstDef, keys::CONST),
    (TypeAliasId, ast::TypeAliasDef, keys::TYPE_ALIAS),
    (ImplId, ast::ImplBlock, keys::IMPL),
    (StructFieldId, ast::RecordFieldDef, keys::RECORD_FIELD),
    (EnumVariantId, ast::EnumVariant, keys::ENUM_VARIANT),
];

// FIXME: use DynMap as well?
impl ToId for ast::MacroCall {
    type ID = MacroDefId;
    fn to_id<DB: HirDatabase>(
        sb: &mut SourceBinder<'_, DB>,
        src: InFile<Self>,
    ) -> Option<Self::ID> {
        let kind = MacroDefKind::Declarative;

        let krate = sb.to_module_def(src.file_id.original_file(sb.db))?.id.krate;

        let ast_id =
            Some(AstId::new(src.file_id, sb.db.ast_id_map(src.file_id).ast_id(&src.value)));

        Some(MacroDefId { krate: Some(krate), ast_id, kind })
    }
}

impl ToDef for ast::BindPat {
    type Def = Local;

    fn to_def<DB: HirDatabase>(sb: &mut SourceBinder<'_, DB>, src: InFile<Self>) -> Option<Local> {
        let file_id = src.file_id;
        let parent: DefWithBodyId = src.value.syntax().ancestors().find_map(|it| {
            let res = match_ast! {
                match it {
                    ast::ConstDef(value) => { sb.to_id(InFile { value, file_id})?.into() },
                    ast::StaticDef(value) => { sb.to_id(InFile { value, file_id})?.into() },
                    ast::FnDef(value) => { sb.to_id(InFile { value, file_id})?.into() },
                    _ => return None,
                }
            };
            Some(res)
        })?;
        let (_body, source_map) = sb.db.body_with_source_map(parent);
        let src = src.map(ast::Pat::from);
        let pat_id = source_map.node_pat(src.as_ref())?;
        Some(Local { parent: parent.into(), pat_id })
    }
}

impl ToDef for ast::TypeParam {
    type Def = TypeParam;

    fn to_def<DB: HirDatabase>(
        sb: &mut SourceBinder<'_, DB>,
        src: InFile<ast::TypeParam>,
    ) -> Option<TypeParam> {
        let mut sb = SourceBinder::new(sb.db);
        let file_id = src.file_id;
        let parent: GenericDefId = src.value.syntax().ancestors().find_map(|it| {
            let res = match_ast! {
                match it {
                    ast::FnDef(value) => { sb.to_id(InFile { value, file_id})?.into() },
                    ast::StructDef(value) => { sb.to_id(InFile { value, file_id})?.into() },
                    ast::EnumDef(value) => { sb.to_id(InFile { value, file_id})?.into() },
                    ast::TraitDef(value) => { sb.to_id(InFile { value, file_id})?.into() },
                    ast::TypeAliasDef(value) => { sb.to_id(InFile { value, file_id})?.into() },
                    ast::ImplBlock(value) => { sb.to_id(InFile { value, file_id})?.into() },
                    _ => return None,
                }
            };
            Some(res)
        })?;
        let &id = sb.child_by_source(parent.into())[keys::TYPE_PARAM].get(&src)?;
        Some(TypeParam { id })
    }
}

impl ToDef for ast::Module {
    type Def = Module;

    fn to_def<DB: HirDatabase>(
        sb: &mut SourceBinder<'_, DB>,
        src: InFile<ast::Module>,
    ) -> Option<Module> {
        {
            let _p = profile("ast::Module::to_def");
            let parent_declaration = src
                .as_ref()
                .map(|it| it.syntax())
                .cloned()
                .ancestors_with_macros(sb.db)
                .skip(1)
                .find_map(|it| {
                    let m = ast::Module::cast(it.value.clone())?;
                    Some(it.with_value(m))
                });

            let parent_module = match parent_declaration {
                Some(parent_declaration) => sb.to_def(parent_declaration),
                None => {
                    let file_id = src.file_id.original_file(sb.db);
                    sb.to_module_def(file_id)
                }
            }?;

            let child_name = src.value.name()?.as_name();
            let def_map = sb.db.crate_def_map(parent_module.id.krate);
            let child_id = def_map[parent_module.id.local_id].children.get(&child_name)?;
            Some(parent_module.with_module_id(*child_id))
        }
    }
}
<commit_msg>Correctly discover module containers<commit_after>//! `SourceBinder` should be the main entry point for getting info about source code.
//! It's main task is to map source syntax trees to hir-level IDs.
//!
//! It is intended to subsume `FromSource` and `SourceAnalyzer`.

use hir_def::{
    child_by_source::ChildBySource,
    dyn_map::DynMap,
    keys::{self, Key},
    resolver::{HasResolver, Resolver},
    ConstId, DefWithBodyId, EnumId, EnumVariantId, FunctionId, GenericDefId, ImplId, ModuleId,
    StaticId, StructFieldId, StructId, TraitId, TypeAliasId, UnionId, VariantId,
};
use hir_expand::{name::AsName, AstId, InFile, MacroDefId, MacroDefKind};
use ra_prof::profile;
use ra_syntax::{
    ast::{self, NameOwner},
    match_ast, AstNode, SyntaxNode, TextUnit,
};
use rustc_hash::FxHashMap;

use crate::{db::HirDatabase, Local, Module, SourceAnalyzer, TypeParam};
use ra_db::FileId;

pub struct SourceBinder<'a, DB> {
    pub db: &'a DB,
    child_by_source_cache: FxHashMap<ChildContainer, DynMap>,
}

impl<DB: HirDatabase> SourceBinder<'_, DB> {
    pub fn new(db: &DB) -> SourceBinder<DB> {
        SourceBinder { db, child_by_source_cache: FxHashMap::default() }
    }

    pub fn analyze(
        &mut self,
        src: InFile<&SyntaxNode>,
        offset: Option<TextUnit>,
    ) -> SourceAnalyzer {
        let _p = profile("SourceBinder::analyzer");
        let container = match self.find_container(src) {
            Some(it) => it,
            None => return SourceAnalyzer::new_for_resolver(Resolver::default(), src),
        };

        let resolver = match container {
            ChildContainer::DefWithBodyId(def) => {
                return SourceAnalyzer::new_for_body(self.db, def, src, offset)
            }
            ChildContainer::TraitId(it) => it.resolver(self.db),
            ChildContainer::ImplId(it) => it.resolver(self.db),
            ChildContainer::ModuleId(it) => it.resolver(self.db),
            ChildContainer::EnumId(it) => it.resolver(self.db),
            ChildContainer::VariantId(it) => it.resolver(self.db),
            ChildContainer::GenericDefId(it) => it.resolver(self.db),
        };
        SourceAnalyzer::new_for_resolver(resolver, src)
    }

    pub fn to_def<T: ToDef>(&mut self, src: InFile<T>) -> Option<T::Def> {
        T::to_def(self, src)
    }

    pub fn to_module_def(&mut self, file: FileId) -> Option<Module> {
        let _p = profile("SourceBinder::to_module_def");
        let (krate, local_id) = self.db.relevant_crates(file).iter().find_map(|&crate_id| {
            let crate_def_map = self.db.crate_def_map(crate_id);
            let local_id = crate_def_map.modules_for_file(file).next()?;
            Some((crate_id, local_id))
        })?;
        Some(Module { id: ModuleId { krate, local_id } })
    }

    fn to_id<T: ToId>(&mut self, src: InFile<T>) -> Option<T::ID> {
        T::to_id(self, src)
    }

    fn find_container(&mut self, src: InFile<&SyntaxNode>) -> Option<ChildContainer> {
        for container in src.cloned().ancestors_with_macros(self.db).skip(1) {
            let res: ChildContainer = match_ast! {
                match (container.value) {
                    ast::TraitDef(it) => {
                        let def: TraitId = self.to_id(container.with_value(it))?;
                        def.into()
                    },
                    ast::ImplBlock(it) => {
                        let def: ImplId = self.to_id(container.with_value(it))?;
                        def.into()
                    },
                    ast::FnDef(it) => {
                        let def: FunctionId = self.to_id(container.with_value(it))?;
                        DefWithBodyId::from(def).into()
                    },
                    ast::StaticDef(it) => {
                        let def: StaticId = self.to_id(container.with_value(it))?;
                        DefWithBodyId::from(def).into()
                    },
                    ast::ConstDef(it) => {
                        let def: ConstId = self.to_id(container.with_value(it))?;
                        DefWithBodyId::from(def).into()
                    },
                    ast::EnumDef(it) => {
                        let def: EnumId = self.to_id(container.with_value(it))?;
                        def.into()
                    },
                    ast::StructDef(it) => {
                        let def: StructId = self.to_id(container.with_value(it))?;
                        VariantId::from(def).into()
                    },
                    ast::UnionDef(it) => {
                        let def: UnionId = self.to_id(container.with_value(it))?;
                        VariantId::from(def).into()
                    },
                    ast::Module(it) => {
                        let def: ModuleId = self.to_id(container.with_value(it))?;
                        def.into()
                    },
                    _ => { continue },
                }
            };
            return Some(res);
        }

        let c = self.to_module_def(src.file_id.original_file(self.db))?;
        Some(c.id.into())
    }

    fn child_by_source(&mut self, container: ChildContainer) -> &DynMap {
        let db = self.db;
        self.child_by_source_cache.entry(container).or_insert_with(|| match container {
            ChildContainer::DefWithBodyId(it) => it.child_by_source(db),
            ChildContainer::ModuleId(it) => it.child_by_source(db),
            ChildContainer::TraitId(it) => it.child_by_source(db),
            ChildContainer::ImplId(it) => it.child_by_source(db),
            ChildContainer::EnumId(it) => it.child_by_source(db),
            ChildContainer::VariantId(it) => it.child_by_source(db),
            ChildContainer::GenericDefId(it) => it.child_by_source(db),
        })
    }
}

pub trait ToId: Sized {
    type ID: Sized + Copy + 'static;
    fn to_id<DB: HirDatabase>(sb: &mut SourceBinder<'_, DB>, src: InFile<Self>)
        -> Option<Self::ID>;
}

pub trait ToDef: Sized + AstNode + 'static {
    type Def;
    fn to_def<DB: HirDatabase>(
        sb: &mut SourceBinder<'_, DB>,
        src: InFile<Self>,
    ) -> Option<Self::Def>;
}

macro_rules! to_def_impls {
    ($(($def:path, $ast:path)),* ,) => {$(
        impl ToDef for $ast {
            type Def = $def;
            fn to_def<DB: HirDatabase>(sb: &mut SourceBinder<'_, DB>, src: InFile<Self>)
                -> Option<Self::Def>
            { sb.to_id(src).map(Into::into) }
        }
    )*}
}

to_def_impls![
    (crate::Module, ast::Module),
    (crate::Struct, ast::StructDef),
    (crate::Enum, ast::EnumDef),
    (crate::Union, ast::UnionDef),
    (crate::Trait, ast::TraitDef),
    (crate::ImplBlock, ast::ImplBlock),
    (crate::TypeAlias, ast::TypeAliasDef),
    (crate::Const, ast::ConstDef),
    (crate::Static, ast::StaticDef),
    (crate::Function, ast::FnDef),
    (crate::StructField, ast::RecordFieldDef),
    (crate::EnumVariant, ast::EnumVariant),
    (crate::MacroDef, ast::MacroCall), // this one is dubious, not all calls are macros
];

#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
enum ChildContainer {
    DefWithBodyId(DefWithBodyId),
    ModuleId(ModuleId),
    TraitId(TraitId),
    ImplId(ImplId),
    EnumId(EnumId),
    VariantId(VariantId),
    /// XXX: this might be the same def as, for example an `EnumId`. However,
    /// here the children generic parameters, and not, eg enum variants.
    GenericDefId(GenericDefId),
}
impl_froms! {
    ChildContainer:
    DefWithBodyId,
    ModuleId,
    TraitId,
    ImplId,
    EnumId,
    VariantId,
    GenericDefId
}

pub trait ToIdByKey: Sized + AstNode + 'static {
    type ID: Sized + Copy + 'static;
    const KEY: Key<Self, Self::ID>;
}

impl<T: ToIdByKey> ToId for T {
    type ID = <T as ToIdByKey>::ID;
    fn to_id<DB: HirDatabase>(
        sb: &mut SourceBinder<'_, DB>,
        src: InFile<Self>,
    ) -> Option<Self::ID> {
        let container = sb.find_container(src.as_ref().map(|it| it.syntax()))?;
        let db = sb.db;
        let dyn_map =
            &*sb.child_by_source_cache.entry(container).or_insert_with(|| match container {
                ChildContainer::DefWithBodyId(it) => it.child_by_source(db),
                ChildContainer::ModuleId(it) => it.child_by_source(db),
                ChildContainer::TraitId(it) => it.child_by_source(db),
                ChildContainer::ImplId(it) => it.child_by_source(db),
                ChildContainer::EnumId(it) => it.child_by_source(db),
                ChildContainer::VariantId(it) => it.child_by_source(db),
                ChildContainer::GenericDefId(it) => it.child_by_source(db),
            });
        dyn_map[T::KEY].get(&src).copied()
    }
}

macro_rules! to_id_key_impls {
    ($(($id:ident, $ast:path, $key:path)),* ,) => {$(
        impl ToIdByKey for $ast {
            type ID = $id;
            const KEY: Key<Self, Self::ID> = $key;
        }
    )*}
}

to_id_key_impls![
    (StructId, ast::StructDef, keys::STRUCT),
    (UnionId, ast::UnionDef, keys::UNION),
    (EnumId, ast::EnumDef, keys::ENUM),
    (TraitId, ast::TraitDef, keys::TRAIT),
    (FunctionId, ast::FnDef, keys::FUNCTION),
    (StaticId, ast::StaticDef, keys::STATIC),
    (ConstId, ast::ConstDef, keys::CONST),
    (TypeAliasId, ast::TypeAliasDef, keys::TYPE_ALIAS),
    (ImplId, ast::ImplBlock, keys::IMPL),
    (StructFieldId, ast::RecordFieldDef, keys::RECORD_FIELD),
    (EnumVariantId, ast::EnumVariant, keys::ENUM_VARIANT),
];

// FIXME: use DynMap as well?
impl ToId for ast::MacroCall {
    type ID = MacroDefId;
    fn to_id<DB: HirDatabase>(
        sb: &mut SourceBinder<'_, DB>,
        src: InFile<Self>,
    ) -> Option<Self::ID> {
        let kind = MacroDefKind::Declarative;

        let krate = sb.to_module_def(src.file_id.original_file(sb.db))?.id.krate;

        let ast_id =
            Some(AstId::new(src.file_id, sb.db.ast_id_map(src.file_id).ast_id(&src.value)));

        Some(MacroDefId { krate: Some(krate), ast_id, kind })
    }
}

impl ToDef for ast::BindPat {
    type Def = Local;

    fn to_def<DB: HirDatabase>(sb: &mut SourceBinder<'_, DB>, src: InFile<Self>) -> Option<Local> {
        let file_id = src.file_id;
        let parent: DefWithBodyId = src.value.syntax().ancestors().find_map(|it| {
            let res = match_ast! {
                match it {
                    ast::ConstDef(value) => { sb.to_id(InFile { value, file_id})?.into() },
                    ast::StaticDef(value) => { sb.to_id(InFile { value, file_id})?.into() },
                    ast::FnDef(value) => { sb.to_id(InFile { value, file_id})?.into() },
                    _ => return None,
                }
            };
            Some(res)
        })?;
        let (_body, source_map) = sb.db.body_with_source_map(parent);
        let src = src.map(ast::Pat::from);
        let pat_id = source_map.node_pat(src.as_ref())?;
        Some(Local { parent: parent.into(), pat_id })
    }
}

impl ToDef for ast::TypeParam {
    type Def = TypeParam;

    fn to_def<DB: HirDatabase>(
        sb: &mut SourceBinder<'_, DB>,
        src: InFile<ast::TypeParam>,
    ) -> Option<TypeParam> {
        let mut sb = SourceBinder::new(sb.db);
        let file_id = src.file_id;
        let parent: GenericDefId = src.value.syntax().ancestors().find_map(|it| {
            let res = match_ast! {
                match it {
                    ast::FnDef(value) => { sb.to_id(InFile { value, file_id})?.into() },
                    ast::StructDef(value) => { sb.to_id(InFile { value, file_id})?.into() },
                    ast::EnumDef(value) => { sb.to_id(InFile { value, file_id})?.into() },
                    ast::TraitDef(value) => { sb.to_id(InFile { value, file_id})?.into() },
                    ast::TypeAliasDef(value) => { sb.to_id(InFile { value, file_id})?.into() },
                    ast::ImplBlock(value) => { sb.to_id(InFile { value, file_id})?.into() },
                    _ => return None,
                }
            };
            Some(res)
        })?;
        let &id = sb.child_by_source(parent.into())[keys::TYPE_PARAM].get(&src)?;
        Some(TypeParam { id })
    }
}

impl ToId for ast::Module {
    type ID = ModuleId;

    fn to_id<DB: HirDatabase>(
        sb: &mut SourceBinder<'_, DB>,
        src: InFile<ast::Module>,
    ) -> Option<ModuleId> {
        {
            let _p = profile("ast::Module::to_def");
            let parent_declaration = src
                .as_ref()
                .map(|it| it.syntax())
                .cloned()
                .ancestors_with_macros(sb.db)
                .skip(1)
                .find_map(|it| {
                    let m = ast::Module::cast(it.value.clone())?;
                    Some(it.with_value(m))
                });

            let parent_module = match parent_declaration {
                Some(parent_declaration) => sb.to_id(parent_declaration)?,
                None => {
                    let file_id = src.file_id.original_file(sb.db);
                    sb.to_module_def(file_id)?.id
                }
            };

            let child_name = src.value.name()?.as_name();
            let def_map = sb.db.crate_def_map(parent_module.krate);
            let child_id = *def_map[parent_module.local_id].children.get(&child_name)?;
            Some(ModuleId { krate: parent_module.krate, local_id: child_id })
        }
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]
#![allow(clippy::new_ret_no_self)]
use std::cmp::min;
use std::fmt;
use xlib_window_system::XlibWindowSystem;
use xlib::Window;

#[derive(Clone, Copy)]
pub struct Rect {
    pub x: u32,
    pub y: u32,
    pub width: u32,
    pub height: u32,
}

impl fmt::Debug for Rect {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "{{ x: {}, y: {}, width: {}, height: {} }}",
               self.x,
               self.y,
               self.width,
               self.height)
    }
}

#[derive(Clone)]
pub enum LayoutMsg {
    Increase,
    Decrease,
    IncreaseMaster,
    DecreaseMaster,
    SplitHorizontal,
    SplitVertical,
    NextLayout,
    PrevLayout,
    FirstLayout,
    LastLayout,
    Custom(String),
}

impl fmt::Debug for LayoutMsg {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            LayoutMsg::Increase => write!(f, "Increase"),
            LayoutMsg::Decrease => write!(f, "Decrease"),
            LayoutMsg::IncreaseMaster => write!(f, "IncreasMaster"),
            LayoutMsg::DecreaseMaster => write!(f, "DecreaseMaster"),
            LayoutMsg::SplitHorizontal => write!(f, "SplitHorizontal"),
            LayoutMsg::SplitVertical => write!(f, "SplitVertical"),
            LayoutMsg::NextLayout => write!(f, "NextLayout"),
            LayoutMsg::PrevLayout => write!(f, "PrevLayout"),
            LayoutMsg::FirstLayout => write!(f, "FirstLayout"),
            LayoutMsg::LastLayout => write!(f, "LastLayout"),
            LayoutMsg::Custom(ref val) => write!(f, "Custom({})", val.clone()),
        }
    }
}

pub trait Layout {
    fn name(&self) -> String;
    fn send_msg(&mut self, LayoutMsg);
    fn apply(&self, &XlibWindowSystem, Rect, &[Window]) -> Vec<Rect>;
    fn copy<'a>(&self) -> Box<dyn Layout + 'a> {
        panic!("")
    }
}

pub struct ChooseLayout<'a> {
    layouts: Vec<Box<dyn Layout + 'a>>,
    current: usize,
}

impl<'a> ChooseLayout<'a> {
    pub fn new(layouts: Vec<Box<dyn Layout + 'a>>) -> Box<dyn Layout + 'a> {
        // add proper error handling
        if layouts.is_empty() {
            panic!("ChooseLayout needs at least one layout");
        }

        Box::new(ChooseLayout {
            layouts,
            current: 0,
        })
    }
}

impl<'a> Layout for ChooseLayout<'a> {
    fn name(&self) -> String {
        self.layouts[self.current].name()
    }

    fn send_msg(&mut self, msg: LayoutMsg) {
        let len = self.layouts.len();

        match msg {
            LayoutMsg::NextLayout => {
                self.current = (self.current + 1) % len;
            }
            LayoutMsg::PrevLayout => {
                self.current = (self.current + len - 1) % len;
            }
            LayoutMsg::FirstLayout => {
                self.current = 0;
            }
            LayoutMsg::LastLayout => {
                self.current = len - 1;
            }
            x => {
                self.layouts[self.current].send_msg(x);
            }
        }
    }

    fn apply(&self, ws: &XlibWindowSystem, area: Rect, windows: &[Window]) -> Vec<Rect> {
        self.layouts[self.current].apply(ws, area, windows)
    }

    fn copy<'b>(&self) -> Box<dyn Layout + 'b> {
        ChooseLayout::new(self.layouts.iter().map(|x| x.copy()).collect())
    }
}

#[derive(Clone, Copy)]
pub struct TallLayout {
    num_masters: usize,
    ratio: f32,
    ratio_increment: f32,
}

impl TallLayout {
    pub fn new<'a>(num_masters: usize, ratio: f32, ratio_increment: f32) -> Box<dyn Layout + 'a> {
        Box::new(TallLayout {
            num_masters,
            ratio,
            ratio_increment,
        })
    }
}

impl Layout for TallLayout {
    fn name(&self) -> String {
        "Tall".to_string()
    }

    fn send_msg(&mut self, msg: LayoutMsg) {
        match msg {
            LayoutMsg::Increase => {
                if self.ratio + self.ratio_increment < 1.0 {
                    self.ratio += self.ratio_increment;
                }
            }
            LayoutMsg::Decrease => {
                if self.ratio - self.ratio_increment > self.ratio_increment {
                    self.ratio -= self.ratio_increment;
                }
            }
            LayoutMsg::IncreaseMaster => self.num_masters += 1,
            LayoutMsg::DecreaseMaster => {
                if self.num_masters > 1 {
                    self.num_masters -= 1;
                }
            }
            _ => {}
        }
    }

    fn apply(&self, _: &XlibWindowSystem, area: Rect, windows: &[Window]) -> Vec<Rect> {
        (0..windows.len())
            .map(|i| {
                if i < self.num_masters {
                    let yoff = area.height / min(self.num_masters, windows.len()) as u32;

                    Rect {
                        x: area.x,
                        y: area.y + (yoff * i as u32),
                        width: (area.width as f32 *
                                (1.0 -
                                 (windows.len() > self.num_masters) as u32 as f32 *
                                 (1.0 - self.ratio)))
                            .floor() as u32,
                        height: yoff,
                    }
                } else {
                    let yoff = area.height / (windows.len() - self.num_masters) as u32;

                    Rect {
                        x: area.x + (area.width as f32 * self.ratio).floor() as u32,
                        y: area.y + (yoff * (i - self.num_masters) as u32),
                        width: (area.width as f32 * (1.0 - self.ratio)).floor() as u32,
                        height: yoff,
                    }
                }
            })
            .collect()
    }

    fn copy<'b>(&self) -> Box<dyn Layout + 'b> {
        Box::new(*self)
    }
}

pub struct StrutLayout<'a> {
    layout: Box<dyn Layout + 'a>,
}

impl<'a> StrutLayout<'a> {
    pub fn new(layout: Box<dyn Layout + 'a>) -> Box<dyn Layout + 'a> {
        Box::new(StrutLayout { layout: layout.copy() })
    }
}

impl<'a> Layout for StrutLayout<'a> {
    fn name(&self) -> String {
        self.layout.name()
    }

    fn send_msg(&mut self, msg: LayoutMsg) {
        self.layout.send_msg(msg);
    }

    fn apply(&self, ws: &XlibWindowSystem, area: Rect, windows: &[Window]) -> Vec<Rect> {
        let mut new_area = Rect {
            x: 0,
            y: 0,
            width: 0,
            height: 0,
        };
        let strut = ws.get_strut(area);

        new_area.x = area.x + strut.0;
        new_area.width = area.width - (strut.0 + strut.1);
        new_area.y = area.y + strut.2;
        new_area.height = area.height - (strut.2 + strut.3);

        self.layout.apply(ws, new_area, windows)
    }

    fn copy<'b>(&self) -> Box<dyn Layout + 'b> {
        StrutLayout::new(self.layout.copy())
    }
}

pub struct GapLayout<'a> {
    gap: u32,
    layout: Box<dyn Layout + 'a>,
}

impl<'a> GapLayout<'a> {
    pub fn new(gap: u32, layout: Box<dyn Layout + 'a>) -> Box<dyn Layout + 'a> {
        Box::new(GapLayout {
            gap,
            layout: layout.copy(),
        })
    }
}

impl<'a> Layout for GapLayout<'a> {
    fn name(&self) -> String {
        self.layout.name()
    }

    fn send_msg(&mut self, msg: LayoutMsg) {
        self.layout.send_msg(msg);
    }

    fn apply(&self, ws: &XlibWindowSystem, area: Rect, windows: &[Window]) -> Vec<Rect> {
        let mut rects = self.layout.apply(ws, area, windows);

        for rect in rects.iter_mut() {
            rect.x += self.gap;
            rect.y += self.gap;
            rect.width -= 2 * self.gap;
            rect.height -= 2 * self.gap;
        }

        rects
    }

    fn copy<'b>(&self) -> Box<dyn Layout + 'b> {
        GapLayout::new(self.gap, self.layout.copy())
    }
}

pub struct MirrorLayout<'a> {
    layout: Box<dyn Layout + 'a>,
}

impl<'a> MirrorLayout<'a> {
    pub fn new(layout: Box<dyn Layout + 'a>) -> Box<dyn Layout + 'a> {
        Box::new(MirrorLayout { layout: layout.copy() })
    }
}

impl<'a> Layout for MirrorLayout<'a> {
    fn name(&self) -> String {
        format!("Mirror({})", self.layout.name())
    }

    fn send_msg(&mut self, msg: LayoutMsg) {
        self.layout.send_msg(msg);
    }

    fn apply(&self, ws: &XlibWindowSystem, area: Rect, windows: &[Window]) -> Vec<Rect> {
        let mut rects = self.layout.apply(ws, area, windows);

        for rect in rects.iter_mut() {
            rect.x = area.width - (rect.x + rect.width);
        }

        rects
    }

    fn copy<'b>(&self) -> Box<dyn Layout + 'b> {
        MirrorLayout::new(self.layout.copy())
    }
}
<commit_msg>Add additional layout function with more access<commit_after>#![allow(dead_code)]
#![allow(clippy::new_ret_no_self)]
use std::cmp::min;
use std::fmt;
use workspaces::Stack;
use xlib_window_system::XlibWindowSystem;
use xlib::Window;

#[derive(Clone, Copy)]
pub struct Rect {
    pub x: u32,
    pub y: u32,
    pub width: u32,
    pub height: u32,
}

impl fmt::Debug for Rect {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "{{ x: {}, y: {}, width: {}, height: {} }}",
               self.x,
               self.y,
               self.width,
               self.height)
    }
}

#[derive(Clone)]
pub enum LayoutMsg {
    Increase,
    Decrease,
    IncreaseMaster,
    DecreaseMaster,
    SplitHorizontal,
    SplitVertical,
    NextLayout,
    PrevLayout,
    FirstLayout,
    LastLayout,
    Custom(String),
}

impl fmt::Debug for LayoutMsg {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            LayoutMsg::Increase => write!(f, "Increase"),
            LayoutMsg::Decrease => write!(f, "Decrease"),
            LayoutMsg::IncreaseMaster => write!(f, "IncreasMaster"),
            LayoutMsg::DecreaseMaster => write!(f, "DecreaseMaster"),
            LayoutMsg::SplitHorizontal => write!(f, "SplitHorizontal"),
            LayoutMsg::SplitVertical => write!(f, "SplitVertical"),
            LayoutMsg::NextLayout => write!(f, "NextLayout"),
            LayoutMsg::PrevLayout => write!(f, "PrevLayout"),
            LayoutMsg::FirstLayout => write!(f, "FirstLayout"),
            LayoutMsg::LastLayout => write!(f, "LastLayout"),
            LayoutMsg::Custom(ref val) => write!(f, "Custom({})", val.clone()),
        }
    }
}

pub trait Layout {
    fn name(&self) -> String;
    fn send_msg(&mut self, LayoutMsg);

    fn apply(&self, area: Rect, _: &XlibWindowSystem, stack: &Stack) -> Vec<Rect> {
        self.simple_apply(area, &stack.visible)
    }

    fn simple_apply(&self, Rect, &[Window]) -> Vec<Rect> {
        Vec::new()
    }

    fn copy<'a>(&self) -> Box<dyn Layout + 'a> {
        panic!("")
    }
}

pub struct ChooseLayout<'a> {
    layouts: Vec<Box<dyn Layout + 'a>>,
    current: usize,
}

impl<'a> ChooseLayout<'a> {
    pub fn new(layouts: Vec<Box<dyn Layout + 'a>>) -> Box<dyn Layout + 'a> {
        // add proper error handling
        if layouts.is_empty() {
            panic!("ChooseLayout needs at least one layout");
        }

        Box::new(ChooseLayout {
            layouts,
            current: 0,
        })
    }
}

impl<'a> Layout for ChooseLayout<'a> {
    fn name(&self) -> String {
        self.layouts[self.current].name()
    }

    fn send_msg(&mut self, msg: LayoutMsg) {
        let len = self.layouts.len();

        match msg {
            LayoutMsg::NextLayout => {
                self.current = (self.current + 1) % len;
            }
            LayoutMsg::PrevLayout => {
                self.current = (self.current + len - 1) % len;
            }
            LayoutMsg::FirstLayout => {
                self.current = 0;
            }
            LayoutMsg::LastLayout => {
                self.current = len - 1;
            }
            x => {
                self.layouts[self.current].send_msg(x);
            }
        }
    }

    fn apply(&self, area: Rect, ws: &XlibWindowSystem, stack: &Stack) -> Vec<Rect> {
        self.layouts[self.current].apply(area, ws, stack)
    }

    fn copy<'b>(&self) -> Box<dyn Layout + 'b> {
        ChooseLayout::new(self.layouts.iter().map(|x| x.copy()).collect())
    }
}

#[derive(Clone, Copy)]
pub struct TallLayout {
    num_masters: usize,
    ratio: f32,
    ratio_increment: f32,
}

impl TallLayout {
    pub fn new<'a>(num_masters: usize, ratio: f32, ratio_increment: f32) -> Box<dyn Layout + 'a> {
        Box::new(TallLayout {
            num_masters,
            ratio,
            ratio_increment,
        })
    }
}

impl Layout for TallLayout {
    fn name(&self) -> String {
        "Tall".to_string()
    }

    fn send_msg(&mut self, msg: LayoutMsg) {
        match msg {
            LayoutMsg::Increase => {
                if self.ratio + self.ratio_increment < 1.0 {
                    self.ratio += self.ratio_increment;
                }
            }
            LayoutMsg::Decrease => {
                if self.ratio - self.ratio_increment > self.ratio_increment {
                    self.ratio -= self.ratio_increment;
                }
            }
            LayoutMsg::IncreaseMaster => self.num_masters += 1,
            LayoutMsg::DecreaseMaster => {
                if self.num_masters > 1 {
                    self.num_masters -= 1;
                }
            }
            _ => {}
        }
    }

    fn simple_apply(&self, area: Rect, windows: &[Window]) -> Vec<Rect> {
        let nwindows = windows.len();

        (0..nwindows)
            .map(|i| {
                if i < self.num_masters {
                    let yoff = area.height / min(self.num_masters, nwindows) as u32;

                    Rect {
                        x: area.x,
                        y: area.y + (yoff * i as u32),
                        width: (area.width as f32 *
                                (1.0 -
                                 (nwindows > self.num_masters) as u32 as f32 *
                                 (1.0 - self.ratio)))
                            .floor() as u32,
                        height: yoff,
                    }
                } else {
                    let yoff = area.height / (nwindows - self.num_masters) as u32;

                    Rect {
                        x: area.x + (area.width as f32 * self.ratio).floor() as u32,
                        y: area.y + (yoff * (i - self.num_masters) as u32),
                        width: (area.width as f32 * (1.0 - self.ratio)).floor() as u32,
                        height: yoff,
                    }
                }
            })
            .collect()
    }

    fn copy<'b>(&self) -> Box<dyn Layout + 'b> {
        Box::new(*self)
    }
}

pub struct StrutLayout<'a> {
    layout: Box<dyn Layout + 'a>,
}

impl<'a> StrutLayout<'a> {
    pub fn new(layout: Box<dyn Layout + 'a>) -> Box<dyn Layout + 'a> {
        Box::new(StrutLayout { layout: layout.copy() })
    }
}

impl<'a> Layout for StrutLayout<'a> {
    fn name(&self) -> String {
        self.layout.name()
    }

    fn send_msg(&mut self, msg: LayoutMsg) {
        self.layout.send_msg(msg);
    }

    fn apply(&self, area: Rect, ws: &XlibWindowSystem, stack: &Stack) -> Vec<Rect> {
        let mut new_area = Rect {
            x: 0,
            y: 0,
            width: 0,
            height: 0,
        };
        let strut = ws.get_strut(area);

        new_area.x = area.x + strut.0;
        new_area.width = area.width - (strut.0 + strut.1);
        new_area.y = area.y + strut.2;
        new_area.height = area.height - (strut.2 + strut.3);

        self.layout.apply(new_area, ws, stack)
    }

    fn copy<'b>(&self) -> Box<dyn Layout + 'b> {
        StrutLayout::new(self.layout.copy())
    }
}

#[derive(Clone, Copy)]
pub struct FullLayout {
    focus: Option<Window>
}

impl FullLayout {
    pub fn new<'a>() -> Box<dyn Layout + 'a> {
        Box::new(FullLayout{
            focus: None
        })
    }
}

impl Layout for FullLayout {
    fn name(&self) -> String {
        "Full".to_string()
    }

    fn send_msg(&mut self, _msg: LayoutMsg) {}

    fn apply(&self, area: Rect, ws: &XlibWindowSystem, stack: &Stack) -> Vec<Rect> {
        stack.visible.iter()
            .map(|&window| {
                if window == stack.focused_window {
                    ws.raise_window(window);
                } else {
                    ws.lower_window(window);
                }

                Rect {
                    x: area.x,
                    y: area.y,
                    width: area.width,
                    height: area.height,
                }
            }).collect()
    }

    fn copy<'b>(&self) -> Box<dyn Layout + 'b> {
        Box::new(*self)
    }
}

pub struct GapLayout<'a> {
    screen_gap: u32,
    window_gap: u32,
    layout: Box<dyn Layout + 'a>,
}

impl<'a> GapLayout<'a> {
    pub fn new(screen_gap: u32, window_gap: u32, layout: Box<dyn Layout + 'a>) -> Box<dyn Layout + 'a> {
        Box::new(GapLayout {
            screen_gap,
            window_gap,
            layout: layout.copy(),
        })
    }
}

impl<'a> Layout for GapLayout<'a> {
    fn name(&self) -> String {
        self.layout.name()
    }

    fn send_msg(&mut self, msg: LayoutMsg) {
        self.layout.send_msg(msg);
    }

    fn apply(&self, area: Rect, ws: &XlibWindowSystem, stack: &Stack) -> Vec<Rect> {
        let area = Rect {
            x: area.x + self.screen_gap,
            y: area.y + self.screen_gap,
            width: area.width - (2 * self.screen_gap),
            height: area.height - (2 * self.screen_gap),
        };

        let mut rects = self.layout.apply(area, ws, stack);

        for rect in rects.iter_mut() {
            rect.x += self.window_gap;
            rect.y += self.window_gap;
            rect.width -= 2 * self.window_gap;
            rect.height -= 2 * self.window_gap;
        }

        rects
    }

    fn copy<'b>(&self) -> Box<dyn Layout + 'b> {
        GapLayout::new(self.screen_gap, self.window_gap, self.layout.copy())
    }
}

pub struct MirrorLayout<'a> {
    layout: Box<dyn Layout + 'a>,
}

impl<'a> MirrorLayout<'a> {
    pub fn new(layout: Box<dyn Layout + 'a>) -> Box<dyn Layout + 'a> {
        Box::new(MirrorLayout { layout: layout.copy() })
    }
}

impl<'a> Layout for MirrorLayout<'a> {
    fn name(&self) -> String {
        format!("Mirror({})", self.layout.name())
    }

    fn send_msg(&mut self, msg: LayoutMsg) {
        self.layout.send_msg(msg);
    }

    fn apply(&self, area: Rect, ws: &XlibWindowSystem, stack: &Stack) -> Vec<Rect> {
        let mut rects = self.layout.apply(area, ws, stack);

        for rect in rects.iter_mut() {
            rect.x = area.width - (rect.x + rect.width);
        }

        rects
    }

    fn copy<'b>(&self) -> Box<dyn Layout + 'b> {
        MirrorLayout::new(self.layout.copy())
    }
}
<|endoftext|>


<commit_before>
use std::num::Float;

use sdl2::surface::Surface;

use world::{RayCastResult};
use math::{LineSeg, Vec2, Mat3};
use game::{Game};

const MAP_SCALE: f32 = 2.0;
const FOV_DIV: f32 = 300.0;
const VISPLANE_DIST: f32 = 300.0;
const PERSON_HEIGHT: f32 = 5.0;

struct RenderContext<'a> {
    pub pixels: &'a mut [u8],
    pub width: isize,
    pub height: isize,
}

impl<'a> Game<'a> {
    pub fn render(&self, sky: &mut Surface, pixels: &mut [u8], w :usize, h: usize) {
        let mut ctx = RenderContext {
            pixels: pixels,
            width: w as isize,
            height: h as isize,
        };

        if self.show_map {
            self.render_map(&mut ctx);
        } else {
            self.render_game(sky, &mut ctx);
        }
    }

    fn render_map(&self, ctx: &mut RenderContext) {
        let trans = Mat3::rotation(-self.face_angle)
                  * Mat3::translation(-self.pos * MAP_SCALE)
                  * Mat3::scale(Vec2::new(MAP_SCALE, MAP_SCALE));

        ctx.clear();
        let (player_x, player_y) = (ctx.width / 2, ctx.height / 2);
        ctx.put_px(player_x as usize, player_y as usize, 0xFF, 0x00, 0x00);

        for wall in self.world.get_walls().iter() {
            ctx.draw_seg(wall.seg.transform(trans), 0xFF, 0x00, 0x00);
        }
    }

    fn render_game(&self, sky: &mut Surface, ctx: &mut RenderContext) {
        let person_height = PERSON_HEIGHT + self.world.get_elevation(self.sector); //+ Float::abs(Float::sin(self.t * 3.0)) * 10.0;
        let looking_offset = -self.look_angle as isize;
        let w = ctx.width as usize;
        let h = ctx.height as usize;

        for x in 0..w {
            let offset = ((x as f32) - (w as f32) / 2.0) / FOV_DIV;

            let mut render_bottom = h as isize;
            let mut render_top = 0;

            for RayCastResult {along, hit_pos, in_info, out_info}
            in self.world.cast_ray(self.sector, self.pos, self.face_angle + offset) {
                let dist = (hit_pos - self.pos).get_length();
                let cast_dist = dist * Float::cos(offset);

                let floor_wall_seg_height = match out_info {
                    Some(i) => i.floor_elev - in_info.floor_elev,
                    None    => in_info.ceiling_elev - in_info.floor_elev,
                };
                let floor_wall_seg_height_px = if floor_wall_seg_height > 0.0 {
                    (VISPLANE_DIST * floor_wall_seg_height / cast_dist) as isize
                } else {
                    0
                };

                let ceiling_wall_seg_height = match out_info {
                    Some(i) => in_info.ceiling_elev - i.ceiling_elev,
                    None    => 0.0
                };
                let ceiling_wall_seg_height_px = if ceiling_wall_seg_height > 0.0 {
                    (VISPLANE_DIST * ceiling_wall_seg_height / cast_dist) as isize
                } else {
                    0
                };

                let middle = (h as isize / 2 + looking_offset);

                let floor_wall_bottom = middle + (VISPLANE_DIST * (person_height - in_info.floor_elev) / cast_dist) as isize;
                let floor_wall_top = floor_wall_bottom - floor_wall_seg_height_px;
                let floor_wall_offset_bottom = if floor_wall_bottom > render_bottom { floor_wall_bottom - render_bottom } else { 0 };

                let draw_floor_wall_top = if floor_wall_top < render_top { render_top } else { floor_wall_top };
                let draw_floor_wall_bottom = if floor_wall_bottom > render_bottom { render_bottom } else { floor_wall_bottom };

                ctx.draw_wall(x, draw_floor_wall_top, draw_floor_wall_bottom, floor_wall_offset_bottom, along, cast_dist);

                let ceiling_wall_top = middle + (VISPLANE_DIST * (person_height - in_info.ceiling_elev) / cast_dist) as isize;
                let ceiling_wall_bottom = ceiling_wall_top + ceiling_wall_seg_height_px;

                let draw_ceiling_wall_top = if ceiling_wall_top < render_top { render_top } else { ceiling_wall_top };
                let draw_ceiling_wall_bottom = if ceiling_wall_bottom > render_bottom { render_bottom } else { ceiling_wall_bottom };

                ctx.draw_wall(x, draw_ceiling_wall_top, draw_ceiling_wall_bottom, 0, along, cast_dist);

                ctx.draw_floor(x, draw_floor_wall_bottom, render_bottom, person_height - in_info.floor_elev, self.pos, hit_pos, offset, -looking_offset);
                ctx.draw_ceiling(x, render_top, draw_ceiling_wall_top, person_height - in_info.ceiling_elev, self.pos, hit_pos, offset, -looking_offset);

                render_top = ceiling_wall_bottom;
                render_bottom = floor_wall_top;
            }

            // SKY
             // if render_bottom > 0 {
             //     for y in 0..render_bottom as usize {
             //         sky.with_lock(|buffer| {
             //             let (r,g,b) = get_px(buffer, x, y, w);
             //             ctx.put_px(x, y, r, g, b);
             //         });
             //     }
             // }
        }

        ctx.draw_seg(LineSeg::new(0.0, -3.0, 0.0, 4.0), 0xff, 0xff, 0xff);
        ctx.draw_seg(LineSeg::new(-3.0, 0.0, 4.0, 0.0), 0xff, 0xff, 0xff);
        ctx.put_px(160, 120, 0x00, 0x00, 0x00);
    }
}

pub fn get_px(tex: &mut [u8], x: usize, y: usize, w: usize) -> (u8,u8,u8) {
    (tex[3*(w*y+x)+0], tex[3*(w*y+x)+1], tex[3*(w*y+x)+2])
}

impl<'a> RenderContext<'a> {
    pub fn put_px(&mut self, x: usize, y: usize, r: u8, g: u8, b: u8) {
        self.pixels[3*(self.width as usize*y+x) + 0] = r;
        self.pixels[3*(self.width as usize*y+x) + 1] = g;
        self.pixels[3*(self.width as usize*y+x) + 2] = b;
    }

    pub fn clear(&mut self) {
        for x in 0..self.width as usize {
            for y in 0..self.height as usize {
                self.put_px(x, y, 0x00, 0x00, 0x00);
            }
        }
    }

    pub fn draw_seg(&mut self, seg: LineSeg, r: u8, g: u8, b: u8) {
        let len = seg.get_length();

        for t in 0..(len as usize) {
            let pt = seg.at(t as f32 / len);
            let ux = (pt.x + (self.width /2) as f32) as usize;
            let uy = (pt.y + (self.height/2) as f32) as usize;

            if ux < self.width as usize && uy < self.height as usize {
                self.put_px(ux, uy, r, g, b);
            }
        }
    }

    pub fn draw_wall(&mut self, x: usize, top: isize, bottom: isize, y_offset: isize, along:f32, cast_dist: f32) {
        if bottom < 0 || top >= self.height { return; }

        let cut_top = if top < 0 { 0 } else { top } as usize;
        let cut_bottom = if bottom > self.height { self.height } else { bottom } as usize;

        for y in cut_top..cut_bottom {
            let yy = ((bottom + y_offset) as usize - y) as f32 * cast_dist / 5000.0;
            let tex_lookup = (along * 25.0) as u8 ^ (512.0*yy) as u8;
            let color = ((tex_lookup as f32) * brightness_from_dist(cast_dist)) as u8;
            self.put_px(x, y, color / 2, color / 2, color);
        }
    }

    pub fn draw_floor(&mut self, x: usize, top: isize, bottom: isize, elevation: f32, pos: Vec2, hit_pos: Vec2, angle: f32, look: isize) {
        if bottom < 0 || top >= self.height { return; }

        let cut_top = if top < self.height / 2 - look { self.height / 2 - look } else { top } as usize;
        let cut_bottom = if bottom > self.height { self.height } else { bottom } as usize;

        for y in cut_top..cut_bottom {
            let dist_floor = VISPLANE_DIST * elevation / ((y as isize + look) as f32 - self.height as f32 / 2.0);
            let floor_pos = pos + (hit_pos - pos).normalize() * dist_floor / Float::cos(angle);
            let tex_lookup = (floor_pos.x * 10.0) as u8 ^ (floor_pos.y * 10.0) as u8;
            let color = (tex_lookup as f32 * brightness_from_dist(dist_floor)) as u8;
            self.put_px(x, y, 0x00, color, 0x00);
        }
    }

    pub fn draw_ceiling(&mut self, x: usize, top: isize, bottom: isize, elevation: f32, pos: Vec2, hit_pos: Vec2, angle: f32, look: isize) {
        if bottom < 0 || top >= self.height { return; }

        let cut_top = if top < 0 { 0 } else { top } as usize;
        let cut_bottom = if bottom > self.height / 2 - look { self.height / 2 - look } else { bottom } as usize;

        for y in cut_top..cut_bottom {
            let dist_floor = VISPLANE_DIST * elevation / ((y as isize + look) as f32 - self.height as f32 / 2.0);
            let floor_pos = pos + (hit_pos - pos).normalize() * dist_floor / Float::cos(angle);
            let tex_lookup = (floor_pos.x * 10.0) as u8 ^ (floor_pos.y * 10.0) as u8;
            let color = (tex_lookup as f32 * brightness_from_dist(dist_floor)) as u8;
            self.put_px(x, y, color, 0x00, 0x00);
        }
    }
}

fn brightness_from_dist(dist: f32) -> f32 {
    (20.0 / dist).min(1.0).max(0.0)
}

<commit_msg>De-duplicate code<commit_after>
use std::num::Float;

use sdl2::surface::Surface;

use world::{RayCastResult};
use math::{LineSeg, Vec2, Mat3};
use game::{Game};

const MAP_SCALE: f32 = 2.0;
const FOV_DIV: f32 = 300.0;
const VISPLANE_DIST: f32 = 300.0;
const PERSON_HEIGHT: f32 = 5.0;

struct RenderContext<'a> {
    pub pixels: &'a mut [u8],
    pub width: isize,
    pub height: isize,
}

impl<'a> Game<'a> {
    pub fn render(&self, sky: &mut Surface, pixels: &mut [u8], w :usize, h: usize) {
        let mut ctx = RenderContext {
            pixels: pixels,
            width: w as isize,
            height: h as isize,
        };

        if self.show_map {
            self.render_map(&mut ctx);
        } else {
            self.render_game(sky, &mut ctx);
        }
    }

    fn render_map(&self, ctx: &mut RenderContext) {
        let trans = Mat3::rotation(-self.face_angle)
                  * Mat3::translation(-self.pos * MAP_SCALE)
                  * Mat3::scale(Vec2::new(MAP_SCALE, MAP_SCALE));

        ctx.clear();
        let (player_x, player_y) = (ctx.width / 2, ctx.height / 2);
        ctx.put_px(player_x as usize, player_y as usize, 0xFF, 0x00, 0x00);

        for wall in self.world.get_walls().iter() {
            ctx.draw_seg(wall.seg.transform(trans), 0xFF, 0x00, 0x00);
        }
    }

    fn render_game(&self, sky: &mut Surface, ctx: &mut RenderContext) {
        let person_height = PERSON_HEIGHT + self.world.get_elevation(self.sector); //+ Float::abs(Float::sin(self.t * 3.0)) * 10.0;
        let looking_offset = -self.look_angle as isize;
        let w = ctx.width as usize;
        let h = ctx.height as usize;

        for x in 0..w {
            let offset = ((x as f32) - (w as f32) / 2.0) / FOV_DIV;

            let mut render_bottom = h as isize;
            let mut render_top = 0;

            for RayCastResult {along, hit_pos, in_info, out_info}
            in self.world.cast_ray(self.sector, self.pos, self.face_angle + offset) {
                let dist = (hit_pos - self.pos).get_length();
                let cast_dist = dist * Float::cos(offset);

                let floor_wall_seg_height = match out_info {
                    Some(i) => i.floor_elev - in_info.floor_elev,
                    None    => in_info.ceiling_elev - in_info.floor_elev,
                };
                let floor_wall_seg_height_px = if floor_wall_seg_height > 0.0 {
                    (VISPLANE_DIST * floor_wall_seg_height / cast_dist) as isize
                } else {
                    0
                };

                let ceiling_wall_seg_height = match out_info {
                    Some(i) => in_info.ceiling_elev - i.ceiling_elev,
                    None    => 0.0
                };
                let ceiling_wall_seg_height_px = if ceiling_wall_seg_height > 0.0 {
                    (VISPLANE_DIST * ceiling_wall_seg_height / cast_dist) as isize
                } else {
                    0
                };

                let middle = (h as isize / 2 + looking_offset);

                let floor_wall_bottom = middle + (VISPLANE_DIST * (person_height - in_info.floor_elev) / cast_dist) as isize;
                let floor_wall_top = floor_wall_bottom - floor_wall_seg_height_px;
                let floor_wall_offset_bottom = if floor_wall_bottom > render_bottom { floor_wall_bottom - render_bottom } else { 0 };

                let draw_floor_wall_top = if floor_wall_top < render_top { render_top } else { floor_wall_top };
                let draw_floor_wall_bottom = if floor_wall_bottom > render_bottom { render_bottom } else { floor_wall_bottom };

                ctx.draw_wall(x, draw_floor_wall_top, draw_floor_wall_bottom, floor_wall_offset_bottom, along, cast_dist);

                let ceiling_wall_top = middle + (VISPLANE_DIST * (person_height - in_info.ceiling_elev) / cast_dist) as isize;
                let ceiling_wall_bottom = ceiling_wall_top + ceiling_wall_seg_height_px;

                let draw_ceiling_wall_top = if ceiling_wall_top < render_top { render_top } else { ceiling_wall_top };
                let draw_ceiling_wall_bottom = if ceiling_wall_bottom > render_bottom { render_bottom } else { ceiling_wall_bottom };

                ctx.draw_wall(x, draw_ceiling_wall_top, draw_ceiling_wall_bottom, 0, along, cast_dist);

                ctx.draw_flat(x, draw_floor_wall_bottom, render_bottom, person_height - in_info.floor_elev, self.pos, hit_pos, offset, -looking_offset);
                ctx.draw_flat(x, render_top, draw_ceiling_wall_top, person_height - in_info.ceiling_elev, self.pos, hit_pos, offset, -looking_offset);

                render_top = ceiling_wall_bottom;
                render_bottom = floor_wall_top;
            }

            // SKY
             // if render_bottom > 0 {
             //     for y in 0..render_bottom as usize {
             //         sky.with_lock(|buffer| {
             //             let (r,g,b) = get_px(buffer, x, y, w);
             //             ctx.put_px(x, y, r, g, b);
             //         });
             //     }
             // }
        }

        ctx.draw_seg(LineSeg::new(0.0, -3.0, 0.0, 4.0), 0xff, 0xff, 0xff);
        ctx.draw_seg(LineSeg::new(-3.0, 0.0, 4.0, 0.0), 0xff, 0xff, 0xff);
        ctx.put_px(160, 120, 0x00, 0x00, 0x00);
    }
}

pub fn get_px(tex: &mut [u8], x: usize, y: usize, w: usize) -> (u8,u8,u8) {
    (tex[3*(w*y+x)+0], tex[3*(w*y+x)+1], tex[3*(w*y+x)+2])
}

impl<'a> RenderContext<'a> {
    pub fn put_px(&mut self, x: usize, y: usize, r: u8, g: u8, b: u8) {
        self.pixels[3*(self.width as usize*y+x) + 0] = r;
        self.pixels[3*(self.width as usize*y+x) + 1] = g;
        self.pixels[3*(self.width as usize*y+x) + 2] = b;
    }

    pub fn clear(&mut self) {
        for x in 0..self.width as usize {
            for y in 0..self.height as usize {
                self.put_px(x, y, 0x00, 0x00, 0x00);
            }
        }
    }

    pub fn draw_seg(&mut self, seg: LineSeg, r: u8, g: u8, b: u8) {
        let len = seg.get_length();

        for t in 0..(len as usize) {
            let pt = seg.at(t as f32 / len);
            let ux = (pt.x + (self.width /2) as f32) as usize;
            let uy = (pt.y + (self.height/2) as f32) as usize;

            if ux < self.width as usize && uy < self.height as usize {
                self.put_px(ux, uy, r, g, b);
            }
        }
    }

    pub fn draw_wall(&mut self, x: usize, top: isize, bottom: isize, y_offset: isize, along:f32, cast_dist: f32) {
        if bottom < 0 || top >= self.height { return; }

        let cut_top = if top < 0 { 0 } else { top } as usize;
        let cut_bottom = if bottom > self.height { self.height } else { bottom } as usize;

        for y in cut_top..cut_bottom {
            let yy = ((bottom + y_offset) as usize - y) as f32 * cast_dist / 5000.0;
            let tex_lookup = (along * 25.0) as u8 ^ (512.0*yy) as u8;
            let color = ((tex_lookup as f32) * brightness_from_dist(cast_dist)) as u8;
            self.put_px(x, y, color / 2, color / 2, color);
        }
    }

    pub fn draw_flat(&mut self, x: usize, top: isize, bottom: isize, elevation: f32, pos: Vec2, hit_pos: Vec2, angle: f32, look: isize) {
        if bottom < 0 || top >= self.height { return; }

        let cut_top = if top < 0 { 0 } else { top } as usize;
        let cut_bottom = if bottom > self.height { self.height } else { bottom } as usize;

        for y in cut_top..cut_bottom {
            let dist_floor = VISPLANE_DIST * elevation / ((y as isize + look) as f32 - self.height as f32 / 2.0);
            let floor_pos = pos + (hit_pos - pos).normalize() * dist_floor / Float::cos(angle);
            let tex_lookup = (floor_pos.x * 10.0) as u8 ^ (floor_pos.y * 10.0) as u8;
            let color = (tex_lookup as f32 * brightness_from_dist(dist_floor)) as u8;
            self.put_px(x, y, 0x00, color, 0x00);
        }
    }
}

fn brightness_from_dist(dist: f32) -> f32 {
    (20.0 / dist).min(1.0).max(0.0)
}

<|endoftext|>


<commit_before>/// ForkTable
/// ---------
///
/// Contains an implementation of the `ForkTable` data structure for storing
/// scoped data.
#[cfg_attr(feature = "nightly",
    stable(feature = "forktable", since = "0.0.1") )]
pub mod forktable;

/// AST
/// ---
///
/// Contains a trait definition for an abstract syntax tree (AST) node.
/// Compilers targeting Seax should provide concrete implementations of this
/// trait for their AST node types. This ensures a consistant interface for
/// Seax compilers.
#[cfg_attr(feature = "nightly",
    stable(feature = "ast", since = "0.0.1") )]
pub mod ast;

// Reexports
pub use self::forktable::ForkTable;
pub use self::ast::ASTNode;

/// Represents an index into the Seax VM's environment stack.
///
/// Since the environment stack is a stack of stacks, an index is represented
/// by two unsigned integers. The first represents the level in the `$e`
/// stack,  and the second represents the index within the list at that level.
#[cfg_attr(feature = "nightly",
    stable(feature = "scope", since = "0.0.1") )]
pub type Index = (u64, u64);

/// The symbol table for bound names is represented as a
/// `ForkTable` mapping `&str` (names) to `(uint,uint)` tuples,
/// representing the location in the `$e` stack storing the value
/// bound to that name.
#[cfg_attr(feature = "nightly",
    stable(feature = "forktable", since = "0.0.1") )]
pub type SymTable<'a> = self::forktable::ForkTable<'a, &'a str, Index>;

/// A `CompileResult` is either `Ok(SVMCell)` or `Err(&str)`
#[cfg_attr(feature = "nightly",
    stable(feature = "compile", since = "0.0.1") )]
pub type CompileResult = Result<Vec<cell::SVMCell>, String>;

/// Trait for a symbol table
#[cfg_attr(feature = "nightly",
    stable(feature = "scope", since = "0.0.1") )]
pub trait Scope<K>
    where K: Eq + std::hash::Hash
{
    /// Bind a name to a scope.
    ///
    /// Returnsthe indices for that name in the SVM environment.
    #[cfg_attr(feature = "nightly",
        stable(feature = "scope", since = "0.0.1") )]
    fn bind(&mut self, name: K, lvl: u64) -> Index;
    /// Look up a name against a scope.
    ///
    /// Returns the indices for that name in the SVM environment,
    /// or None if that name is unbound.
    #[cfg_attr(feature = "nightly",
        stable(feature = "scope", since = "0.0.1") )]
    fn lookup(&self, name: &K)            -> Option<Index>;
}
<commit_msg>Fix some namespace issues in compiler_tools<commit_after>use std::hash::Hash;
use super::SVMCell;

/// ForkTable
/// ---------
///
/// Contains an implementation of the `ForkTable` data structure for storing
/// scoped data.
#[cfg_attr(feature = "nightly",
    stable(feature = "forktable", since = "0.0.1") )]
pub mod forktable;

/// AST
/// ---
///
/// Contains a trait definition for an abstract syntax tree (AST) node.
/// Compilers targeting Seax should provide concrete implementations of this
/// trait for their AST node types. This ensures a consistant interface for
/// Seax compilers.
#[cfg_attr(feature = "nightly",
    stable(feature = "ast", since = "0.0.1") )]
pub mod ast;

// Reexports
pub use self::forktable::ForkTable;
pub use self::ast::ASTNode;

/// Represents an index into the Seax VM's environment stack.
///
/// Since the environment stack is a stack of stacks, an index is represented
/// by two unsigned integers. The first represents the level in the `$e`
/// stack,  and the second represents the index within the list at that level.
#[cfg_attr(feature = "nightly",
    stable(feature = "scope", since = "0.0.1") )]
pub type Index = (u64, u64);

/// The symbol table for bound names is represented as a
/// `ForkTable` mapping `&str` (names) to `(uint,uint)` tuples,
/// representing the location in the `$e` stack storing the value
/// bound to that name.
#[cfg_attr(feature = "nightly",
    stable(feature = "forktable", since = "0.0.1") )]
pub type SymTable<'a> = forktable::ForkTable<'a, &'a str, Index>;

/// A `CompileResult` is either `Ok(SVMCell)` or `Err(&str)`
#[cfg_attr(feature = "nightly",
    stable(feature = "compile", since = "0.0.1") )]
pub type CompileResult = Result<Vec<SVMCell>, String>;

/// Trait for a symbol table
#[cfg_attr(feature = "nightly",
    stable(feature = "scope", since = "0.0.1") )]
pub trait Scope<K>
    where K: Eq + Hash
{
    /// Bind a name to a scope.
    ///
    /// Returnsthe indices for that name in the SVM environment.
    #[cfg_attr(feature = "nightly",
        stable(feature = "scope", since = "0.0.1") )]
    fn bind(&mut self, name: K, lvl: u64) -> Index;
    /// Look up a name against a scope.
    ///
    /// Returns the indices for that name in the SVM environment,
    /// or None if that name is unbound.
    #[cfg_attr(feature = "nightly",
        stable(feature = "scope", since = "0.0.1") )]
    fn lookup(&self, name: &K)            -> Option<Index>;
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::error::Error;
use std::fmt;
use std::sync::Arc;

use iron::{Request, Response, Handler, IronResult, IronError};
use iron::{status, method, headers};
use iron::typemap::Key;
use iron::modifiers::Redirect;
use iron::Url;

use recognizer::Router as Recognizer;
use recognizer::{Match, Params};

pub struct RouterInner {
    // The routers, specialized by method.
    pub routers: HashMap<method::Method, Recognizer<Box<Handler>>>,
    // Routes that accept any method.
    pub wildcard: Recognizer<Box<Handler>>,
    // Used in URL generation.
    pub route_ids: HashMap<String, String>
}

/// `Router` provides an interface for creating complex routes as middleware
/// for the Iron framework.
pub struct Router {
    inner: Arc<RouterInner>
}

impl Router {
    /// Construct a new, empty `Router`.
    ///
    /// ```
    /// # use router::Router;
    /// let router = Router::new();
    /// ```
    pub fn new() -> Router {
        Router {
            inner: Arc::new(RouterInner {
                routers: HashMap::new(),
                wildcard: Recognizer::new(),
                route_ids: HashMap::new()
            })
        }
    }

    fn mut_inner(&mut self) -> &mut RouterInner {
        Arc::get_mut(&mut self.inner).expect("Cannot modify router at this point.")
    }

    /// Add a new route to a `Router`, matching both a method and glob pattern.
    ///
    /// `route` supports glob patterns: `*` for a single wildcard segment and
    /// `:param` for matching storing that segment of the request url in the `Params`
    /// object, which is stored in the request `extensions`.
    ///
    /// For instance, to route `Get` requests on any route matching
    /// `/users/:userid/:friend` and store `userid` and `friend` in
    /// the exposed Params object:
    ///
    /// ```ignore
    /// let mut router = Router::new();
    /// router.route(method::Get, "/users/:userid/:friendid", controller, "user_friend");
    /// ```
    ///
    /// `route_id` is a unique name for your route, and is used when generating an URL with
    /// `url_for`.
    ///
    /// The controller provided to route can be any `Handler`, which allows
    /// extreme flexibility when handling routes. For instance, you could provide
    /// a `Chain`, a `Handler`, which contains an authorization middleware and
    /// a controller function, so that you can confirm that the request is
    /// authorized for this route before handling it.
    pub fn route<S: AsRef<str>, H: Handler, I: AsRef<str>>(&mut self, method: method::Method, glob: S, handler: H, route_id: I) -> &mut Router {
        self.mut_inner().routers
            .entry(method)
            .or_insert(Recognizer::new())
            .add(glob.as_ref(), Box::new(handler));
        self.route_id(route_id.as_ref(), glob.as_ref());
        self
    }

    fn route_id(&mut self, id: &str, glob: &str) {
        let mut mut_inner = self.mut_inner();
        let ref mut route_ids = mut_inner.route_ids;

        match route_ids.get(id) {
            Some(other_glob) if glob != other_glob => panic!("Duplicate route_id: {}", id),
            _ => ()
        };

        route_ids.insert(id.to_owned(), glob.to_owned());
    }

    /// Like route, but specialized to the `Get` method.
    pub fn get<S: AsRef<str>, H: Handler, I: AsRef<str>>(&mut self, glob: S, handler: H, route_id: I) -> &mut Router {
        self.route(method::Get, glob, handler, route_id)
    }

    /// Like route, but specialized to the `Post` method.
    pub fn post<S: AsRef<str>, H: Handler, I: AsRef<str>>(&mut self, glob: S, handler: H, route_id: I) -> &mut Router {
        self.route(method::Post, glob, handler, route_id)
    }

    /// Like route, but specialized to the `Put` method.
    pub fn put<S: AsRef<str>, H: Handler, I: AsRef<str>>(&mut self, glob: S, handler: H, route_id: I) -> &mut Router {
        self.route(method::Put, glob, handler, route_id)
    }

    /// Like route, but specialized to the `Delete` method.
    pub fn delete<S: AsRef<str>, H: Handler, I: AsRef<str>>(&mut self, glob: S, handler: H, route_id: I) -> &mut Router {
        self.route(method::Delete, glob, handler, route_id)
    }

    /// Like route, but specialized to the `Head` method.
    pub fn head<S: AsRef<str>, H: Handler, I: AsRef<str>>(&mut self, glob: S, handler: H, route_id: I) -> &mut Router {
        self.route(method::Head, glob, handler, route_id)
    }

    /// Like route, but specialized to the `Patch` method.
    pub fn patch<S: AsRef<str>, H: Handler, I: AsRef<str>>(&mut self, glob: S, handler: H, route_id: I) -> &mut Router {
        self.route(method::Patch, glob, handler, route_id)
    }

    /// Like route, but specialized to the `Options` method.
    pub fn options<S: AsRef<str>, H: Handler, I: AsRef<str>>(&mut self, glob: S, handler: H, route_id: I) -> &mut Router {
        self.route(method::Options, glob, handler, route_id)
    }

    /// Route will match any method, including gibberish.
    /// In case of ambiguity, handlers specific to methods will be preferred.
    pub fn any<S: AsRef<str>, H: Handler, I: AsRef<str>>(&mut self, glob: S, handler: H, route_id: I) -> &mut Router {
        self.mut_inner().wildcard.add(glob.as_ref(), Box::new(handler));
        self.route_id(route_id.as_ref(), glob.as_ref());
        self
    }

    fn recognize(&self, method: &method::Method, path: &str)
                     -> Option<Match<&Box<Handler>>> {
        self.inner.routers.get(method).and_then(|router| router.recognize(path).ok())
            .or(self.inner.wildcard.recognize(path).ok())
    }

    fn handle_options(&self, path: &str) -> Response {
        static METHODS: &'static [method::Method] =
            &[method::Get, method::Post, method::Post, method::Put,
              method::Delete, method::Head, method::Patch];

        // Get all the available methods and return them.
        let mut options = vec![];

        for method in METHODS.iter() {
            self.inner.routers.get(method).map(|router| {
                if let Some(_) = router.recognize(path).ok() {
                    options.push(method.clone());
                }
            });
        }
        // If GET is there, HEAD is also there.
        if options.contains(&method::Get) && !options.contains(&method::Head) {
            options.push(method::Head);
        }

        let mut res = Response::with(status::Ok);
        res.headers.set(headers::Allow(options));
        res
    }

    // Tests for a match by adding or removing a trailing slash.
    fn redirect_slash(&self, req : &Request) -> Option<IronError> {
        let mut url = req.url.clone();
        let mut path = url.path().join("/");

        if let Some(last_char) = path.chars().last() {
            // Unwrap generic URL to get access to its path components.
            let mut generic_url = url.into_generic_url();
            {
                let mut path_segments = generic_url.path_segments_mut().unwrap();
                if last_char == '/' {
                    // We didn't recognize anything without a trailing slash; try again with one appended.
                    path.pop();
                    path_segments.pop();
                } else {
                    // We didn't recognize anything with a trailing slash; try again without it.
                    path.push('/');
                    path_segments.push("");
                }
            }
            url = Url::from_generic_url(generic_url).unwrap();
        }

        self.recognize(&req.method, &path).and(
            Some(IronError::new(TrailingSlash,
                                (status::MovedPermanently, Redirect(url))))
        )
    }

    fn handle_method(&self, req: &mut Request, path: &str) -> Option<IronResult<Response>> {
        if let Some(matched) = self.recognize(&req.method, path) {
            req.extensions.insert::<Router>(matched.params);
            req.extensions.insert::<RouterInner>(self.inner.clone());
            Some(matched.handler.handle(req))
        } else { self.redirect_slash(req).and_then(|redirect| Some(Err(redirect))) }
    }
}

impl Key for Router { type Value = Params; }

impl Key for RouterInner { type Value = Arc<RouterInner>; }

impl Handler for Router {
    fn handle(&self, req: &mut Request) -> IronResult<Response> {
        let path = req.url.path().join("/");

        self.handle_method(req, &path).unwrap_or_else(||
            match req.method {
                method::Options => Ok(self.handle_options(&path)),
                // For HEAD, fall back to GET. Hyper ensures no response body is written.
                method::Head => {
                    req.method = method::Get;
                    self.handle_method(req, &path).unwrap_or(
                        Err(IronError::new(NoRoute, status::NotFound))
                    )
                }
                _ => Err(IronError::new(NoRoute, status::NotFound))
            }
        )
    }
}

/// The error thrown by router if there is no matching route,
/// it is always accompanied by a NotFound response.
#[derive(Debug, PartialEq, Eq)]
pub struct NoRoute;

impl fmt::Display for NoRoute {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str("No matching route found.")
    }
}

impl Error for NoRoute {
    fn description(&self) -> &str { "No Route" }
}

/// The error thrown by router if a request was redirected
/// by adding or removing a trailing slash.
#[derive(Debug, PartialEq, Eq)]
pub struct TrailingSlash;

impl fmt::Display for TrailingSlash {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str("The request had a trailing slash.")
    }
}

impl Error for TrailingSlash {
    fn description(&self) -> &str { "Trailing Slash" }
}
<commit_msg>fix duplicate POST in handle_options<commit_after>use std::collections::HashMap;
use std::error::Error;
use std::fmt;
use std::sync::Arc;

use iron::{Request, Response, Handler, IronResult, IronError};
use iron::{status, method, headers};
use iron::typemap::Key;
use iron::modifiers::Redirect;
use iron::Url;

use recognizer::Router as Recognizer;
use recognizer::{Match, Params};

pub struct RouterInner {
    // The routers, specialized by method.
    pub routers: HashMap<method::Method, Recognizer<Box<Handler>>>,
    // Routes that accept any method.
    pub wildcard: Recognizer<Box<Handler>>,
    // Used in URL generation.
    pub route_ids: HashMap<String, String>
}

/// `Router` provides an interface for creating complex routes as middleware
/// for the Iron framework.
pub struct Router {
    inner: Arc<RouterInner>
}

impl Router {
    /// Construct a new, empty `Router`.
    ///
    /// ```
    /// # use router::Router;
    /// let router = Router::new();
    /// ```
    pub fn new() -> Router {
        Router {
            inner: Arc::new(RouterInner {
                routers: HashMap::new(),
                wildcard: Recognizer::new(),
                route_ids: HashMap::new()
            })
        }
    }

    fn mut_inner(&mut self) -> &mut RouterInner {
        Arc::get_mut(&mut self.inner).expect("Cannot modify router at this point.")
    }

    /// Add a new route to a `Router`, matching both a method and glob pattern.
    ///
    /// `route` supports glob patterns: `*` for a single wildcard segment and
    /// `:param` for matching storing that segment of the request url in the `Params`
    /// object, which is stored in the request `extensions`.
    ///
    /// For instance, to route `Get` requests on any route matching
    /// `/users/:userid/:friend` and store `userid` and `friend` in
    /// the exposed Params object:
    ///
    /// ```ignore
    /// let mut router = Router::new();
    /// router.route(method::Get, "/users/:userid/:friendid", controller, "user_friend");
    /// ```
    ///
    /// `route_id` is a unique name for your route, and is used when generating an URL with
    /// `url_for`.
    ///
    /// The controller provided to route can be any `Handler`, which allows
    /// extreme flexibility when handling routes. For instance, you could provide
    /// a `Chain`, a `Handler`, which contains an authorization middleware and
    /// a controller function, so that you can confirm that the request is
    /// authorized for this route before handling it.
    pub fn route<S: AsRef<str>, H: Handler, I: AsRef<str>>(&mut self, method: method::Method, glob: S, handler: H, route_id: I) -> &mut Router {
        self.mut_inner().routers
            .entry(method)
            .or_insert(Recognizer::new())
            .add(glob.as_ref(), Box::new(handler));
        self.route_id(route_id.as_ref(), glob.as_ref());
        self
    }

    fn route_id(&mut self, id: &str, glob: &str) {
        let mut mut_inner = self.mut_inner();
        let ref mut route_ids = mut_inner.route_ids;

        match route_ids.get(id) {
            Some(other_glob) if glob != other_glob => panic!("Duplicate route_id: {}", id),
            _ => ()
        };

        route_ids.insert(id.to_owned(), glob.to_owned());
    }

    /// Like route, but specialized to the `Get` method.
    pub fn get<S: AsRef<str>, H: Handler, I: AsRef<str>>(&mut self, glob: S, handler: H, route_id: I) -> &mut Router {
        self.route(method::Get, glob, handler, route_id)
    }

    /// Like route, but specialized to the `Post` method.
    pub fn post<S: AsRef<str>, H: Handler, I: AsRef<str>>(&mut self, glob: S, handler: H, route_id: I) -> &mut Router {
        self.route(method::Post, glob, handler, route_id)
    }

    /// Like route, but specialized to the `Put` method.
    pub fn put<S: AsRef<str>, H: Handler, I: AsRef<str>>(&mut self, glob: S, handler: H, route_id: I) -> &mut Router {
        self.route(method::Put, glob, handler, route_id)
    }

    /// Like route, but specialized to the `Delete` method.
    pub fn delete<S: AsRef<str>, H: Handler, I: AsRef<str>>(&mut self, glob: S, handler: H, route_id: I) -> &mut Router {
        self.route(method::Delete, glob, handler, route_id)
    }

    /// Like route, but specialized to the `Head` method.
    pub fn head<S: AsRef<str>, H: Handler, I: AsRef<str>>(&mut self, glob: S, handler: H, route_id: I) -> &mut Router {
        self.route(method::Head, glob, handler, route_id)
    }

    /// Like route, but specialized to the `Patch` method.
    pub fn patch<S: AsRef<str>, H: Handler, I: AsRef<str>>(&mut self, glob: S, handler: H, route_id: I) -> &mut Router {
        self.route(method::Patch, glob, handler, route_id)
    }

    /// Like route, but specialized to the `Options` method.
    pub fn options<S: AsRef<str>, H: Handler, I: AsRef<str>>(&mut self, glob: S, handler: H, route_id: I) -> &mut Router {
        self.route(method::Options, glob, handler, route_id)
    }

    /// Route will match any method, including gibberish.
    /// In case of ambiguity, handlers specific to methods will be preferred.
    pub fn any<S: AsRef<str>, H: Handler, I: AsRef<str>>(&mut self, glob: S, handler: H, route_id: I) -> &mut Router {
        self.mut_inner().wildcard.add(glob.as_ref(), Box::new(handler));
        self.route_id(route_id.as_ref(), glob.as_ref());
        self
    }

    fn recognize(&self, method: &method::Method, path: &str)
                     -> Option<Match<&Box<Handler>>> {
        self.inner.routers.get(method).and_then(|router| router.recognize(path).ok())
            .or(self.inner.wildcard.recognize(path).ok())
    }

    fn handle_options(&self, path: &str) -> Response {
        static METHODS: &'static [method::Method] =
            &[method::Get, method::Post, method::Put,
              method::Delete, method::Head, method::Patch];

        // Get all the available methods and return them.
        let mut options = vec![];

        for method in METHODS.iter() {
            self.inner.routers.get(method).map(|router| {
                if let Some(_) = router.recognize(path).ok() {
                    options.push(method.clone());
                }
            });
        }
        // If GET is there, HEAD is also there.
        if options.contains(&method::Get) && !options.contains(&method::Head) {
            options.push(method::Head);
        }

        let mut res = Response::with(status::Ok);
        res.headers.set(headers::Allow(options));
        res
    }

    // Tests for a match by adding or removing a trailing slash.
    fn redirect_slash(&self, req : &Request) -> Option<IronError> {
        let mut url = req.url.clone();
        let mut path = url.path().join("/");

        if let Some(last_char) = path.chars().last() {
            // Unwrap generic URL to get access to its path components.
            let mut generic_url = url.into_generic_url();
            {
                let mut path_segments = generic_url.path_segments_mut().unwrap();
                if last_char == '/' {
                    // We didn't recognize anything without a trailing slash; try again with one appended.
                    path.pop();
                    path_segments.pop();
                } else {
                    // We didn't recognize anything with a trailing slash; try again without it.
                    path.push('/');
                    path_segments.push("");
                }
            }
            url = Url::from_generic_url(generic_url).unwrap();
        }

        self.recognize(&req.method, &path).and(
            Some(IronError::new(TrailingSlash,
                                (status::MovedPermanently, Redirect(url))))
        )
    }

    fn handle_method(&self, req: &mut Request, path: &str) -> Option<IronResult<Response>> {
        if let Some(matched) = self.recognize(&req.method, path) {
            req.extensions.insert::<Router>(matched.params);
            req.extensions.insert::<RouterInner>(self.inner.clone());
            Some(matched.handler.handle(req))
        } else { self.redirect_slash(req).and_then(|redirect| Some(Err(redirect))) }
    }
}

impl Key for Router { type Value = Params; }

impl Key for RouterInner { type Value = Arc<RouterInner>; }

impl Handler for Router {
    fn handle(&self, req: &mut Request) -> IronResult<Response> {
        let path = req.url.path().join("/");

        self.handle_method(req, &path).unwrap_or_else(||
            match req.method {
                method::Options => Ok(self.handle_options(&path)),
                // For HEAD, fall back to GET. Hyper ensures no response body is written.
                method::Head => {
                    req.method = method::Get;
                    self.handle_method(req, &path).unwrap_or(
                        Err(IronError::new(NoRoute, status::NotFound))
                    )
                }
                _ => Err(IronError::new(NoRoute, status::NotFound))
            }
        )
    }
}

/// The error thrown by router if there is no matching route,
/// it is always accompanied by a NotFound response.
#[derive(Debug, PartialEq, Eq)]
pub struct NoRoute;

impl fmt::Display for NoRoute {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str("No matching route found.")
    }
}

impl Error for NoRoute {
    fn description(&self) -> &str { "No Route" }
}

/// The error thrown by router if a request was redirected
/// by adding or removing a trailing slash.
#[derive(Debug, PartialEq, Eq)]
pub struct TrailingSlash;

impl fmt::Display for TrailingSlash {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str("The request had a trailing slash.")
    }
}

impl Error for TrailingSlash {
    fn description(&self) -> &str { "Trailing Slash" }
}

#[cfg(test)]
mod test {
    use super::Router;
    use iron::{headers, method, status, Request, Response};

    #[test]
    fn test_handle_options_post() {
        let mut router = Router::new();
        router.post("/", |_: &mut Request| {
            Ok(Response::with((status::Ok, "")))
        }, "");
        let resp = router.handle_options("/");
        let headers = resp.headers.get::<headers::Allow>().unwrap();
        let expected = headers::Allow(vec![method::Method::Post]);
        assert_eq!(&expected, headers);
    }

    #[test]
    fn test_handle_options_get_head() {
        let mut router = Router::new();
        router.get("/", |_: &mut Request| {
            Ok(Response::with((status::Ok, "")))
        }, "");
        let resp = router.handle_options("/");
        let headers = resp.headers.get::<headers::Allow>().unwrap();
        let expected = headers::Allow(vec![method::Method::Get, method::Method::Head]);
        assert_eq!(&expected, headers);
    }
}
<|endoftext|>