<commit_before>//! Describes items defined or visible (ie, imported) in a certain scope.
//! This is shared between modules and blocks.

use std::collections::hash_map::Entry;

use hir_expand::name::Name;
use once_cell::sync::Lazy;
use ra_db::CrateId;
use rustc_hash::{FxHashMap, FxHashSet};
use test_utils::mark;

use crate::{
    db::DefDatabase, per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType, HasModule, ImplId,
    LocalModuleId, Lookup, MacroDefId, ModuleDefId, TraitId,
};

#[derive(Copy, Clone)]
pub(crate) enum ImportType {
    Glob,
    Named,
}

#[derive(Debug, Default)]
pub struct PerNsGlobImports {
    types: FxHashSet<(LocalModuleId, Name)>,
    values: FxHashSet<(LocalModuleId, Name)>,
    macros: FxHashSet<(LocalModuleId, Name)>,
}

#[derive(Debug, Default, PartialEq, Eq)]
pub struct ItemScope {
    types: FxHashMap<Name, (ModuleDefId, Visibility)>,
    values: FxHashMap<Name, (ModuleDefId, Visibility)>,
    macros: FxHashMap<Name, (MacroDefId, Visibility)>,
    unresolved: FxHashSet<Name>,

    defs: Vec<ModuleDefId>,
    impls: Vec<ImplId>,
    /// Macros visible in current module in legacy textual scope
    ///
    /// For macros invoked by an unqualified identifier like `bar!()`, `legacy_macros` will be searched in first.
    /// If it yields no result, then it turns to module scoped `macros`.
    /// It macros with name qualified with a path like `crate::foo::bar!()`, `legacy_macros` will be skipped,
    /// and only normal scoped `macros` will be searched in.
    ///
    /// Note that this automatically inherit macros defined textually before the definition of module itself.
    ///
    /// Module scoped macros will be inserted into `items` instead of here.
    // FIXME: Macro shadowing in one module is not properly handled. Non-item place macros will
    // be all resolved to the last one defined if shadowing happens.
    legacy_macros: FxHashMap<Name, MacroDefId>,
}

pub(crate) static BUILTIN_SCOPE: Lazy<FxHashMap<Name, PerNs>> = Lazy::new(|| {
    BuiltinType::ALL
        .iter()
        .map(|(name, ty)| (name.clone(), PerNs::types(ty.clone().into(), Visibility::Public)))
        .collect()
});

/// Shadow mode for builtin type which can be shadowed by module.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub(crate) enum BuiltinShadowMode {
    /// Prefer user-defined modules (or other types) over builtins.
    Module,
    /// Prefer builtins over user-defined modules (but not other types).
    Other,
}

/// Legacy macros can only be accessed through special methods like `get_legacy_macros`.
/// Other methods will only resolve values, types and module scoped macros only.
impl ItemScope {
    pub fn entries<'a>(&'a self) -> impl Iterator<Item = (&'a Name, PerNs)> + 'a {
        // FIXME: shadowing
        let keys: FxHashSet<_> = self
            .types
            .keys()
            .chain(self.values.keys())
            .chain(self.macros.keys())
            .chain(self.unresolved.iter())
            .collect();

        keys.into_iter().map(move |name| (name, self.get(name)))
    }

    pub fn entries_without_primitives<'a>(
        &'a self,
    ) -> impl Iterator<Item = (&'a Name, PerNs)> + 'a {
        self.entries()
    }

    pub fn declarations(&self) -> impl Iterator<Item = ModuleDefId> + '_ {
        self.defs.iter().copied()
    }

    pub fn impls(&self) -> impl Iterator<Item = ImplId> + ExactSizeIterator + '_ {
        self.impls.iter().copied()
    }

    pub fn visibility_of(&self, def: ModuleDefId) -> Option<Visibility> {
        self.name_of(ItemInNs::Types(def))
            .or_else(|| self.name_of(ItemInNs::Values(def)))
            .map(|(_, v)| v)
    }

    /// Iterate over all module scoped macros
    pub(crate) fn macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroDefId)> + 'a {
        self.entries().filter_map(|(name, def)| def.take_macros().map(|macro_| (name, macro_)))
    }

    /// Iterate over all legacy textual scoped macros visible at the end of the module
    pub(crate) fn legacy_macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroDefId)> + 'a {
        self.legacy_macros.iter().map(|(name, def)| (name, *def))
    }

    /// Get a name from current module scope, legacy macros are not included
    pub(crate) fn get(&self, name: &Name) -> PerNs {
        PerNs {
            types: self.types.get(name).copied(),
            values: self.values.get(name).copied(),
            macros: self.macros.get(name).copied(),
        }
    }

    pub(crate) fn name_of(&self, item: ItemInNs) -> Option<(&Name, Visibility)> {
        for (name, per_ns) in self.entries() {
            if let Some(vis) = item.match_with(per_ns) {
                return Some((name, vis));
            }
        }
        None
    }

    pub(crate) fn traits<'a>(&'a self) -> impl Iterator<Item = TraitId> + 'a {
        self.types.values().filter_map(|(def, _)| match def {
            ModuleDefId::TraitId(t) => Some(*t),
            _ => None,
        })
    }

    pub(crate) fn define_def(&mut self, def: ModuleDefId) {
        self.defs.push(def)
    }

    pub(crate) fn get_legacy_macro(&self, name: &Name) -> Option<MacroDefId> {
        self.legacy_macros.get(name).copied()
    }

    pub(crate) fn define_impl(&mut self, imp: ImplId) {
        self.impls.push(imp)
    }

    pub(crate) fn define_legacy_macro(&mut self, name: Name, mac: MacroDefId) {
        self.legacy_macros.insert(name, mac);
    }

    pub(crate) fn push_res(&mut self, name: Name, def: PerNs) -> bool {
        let mut changed = false;

        if let Some(types) = def.types {
            match self.types.entry(name.clone()) {
                Entry::Occupied(_) => {}
                Entry::Vacant(e) => {
                    e.insert(types);
                    changed = true;
                }
            }
        }
        if let Some(values) = def.values {
            match self.values.entry(name.clone()) {
                Entry::Occupied(_) => {}
                Entry::Vacant(e) => {
                    e.insert(values);
                    changed = true;
                }
            }
        }
        if let Some(macros) = def.macros {
            match self.macros.entry(name.clone()) {
                Entry::Occupied(_) => {}
                Entry::Vacant(e) => {
                    e.insert(macros);
                    changed = true;
                }
            }
        }

        if def.is_none() {
            if self.unresolved.insert(name) {
                changed = true;
            }
        }

        changed
    }

    pub(crate) fn push_res_with_import(
        &mut self,
        glob_imports: &mut PerNsGlobImports,
        lookup: (LocalModuleId, Name),
        def: PerNs,
        def_import_type: ImportType,
    ) -> bool {
        let mut changed = false;

        macro_rules! check_changed {
            (
                $changed:ident,
                ( $this:ident / $def:ident ) . $field:ident,
                $glob_imports:ident [ $lookup:ident ],
                $def_import_type:ident
            ) => {{
                let existing = $this.$field.entry($lookup.1.clone());
                match (existing, $def.$field) {
                    (Entry::Vacant(entry), Some(_)) => {
                        match $def_import_type {
                            ImportType::Glob => {
                                $glob_imports.$field.insert($lookup.clone());
                            }
                            ImportType::Named => {
                                $glob_imports.$field.remove(&$lookup);
                            }
                        }

                        if let Some(fld) = $def.$field {
                            entry.insert(fld);
                        }
                        $changed = true;
                    }
                    (Entry::Occupied(mut entry), Some(_))
                        if $glob_imports.$field.contains(&$lookup)
                            && matches!($def_import_type, ImportType::Named) =>
                    {
                        mark::hit!(import_shadowed);
                        $glob_imports.$field.remove(&$lookup);
                        if let Some(fld) = $def.$field {
                            entry.insert(fld);
                        }
                        $changed = true;
                    }
                    _ => {}
                }
            }};
        }

        check_changed!(changed, (self / def).types, glob_imports[lookup], def_import_type);
        check_changed!(changed, (self / def).values, glob_imports[lookup], def_import_type);
        check_changed!(changed, (self / def).macros, glob_imports[lookup], def_import_type);

        if def.is_none() {
            if self.unresolved.insert(lookup.1) {
                changed = true;
            }
        }

        changed
    }

    pub(crate) fn resolutions<'a>(&'a self) -> impl Iterator<Item = (Name, PerNs)> + 'a {
        self.entries().map(|(name, res)| (name.clone(), res))
    }

    pub(crate) fn collect_legacy_macros(&self) -> FxHashMap<Name, MacroDefId> {
        self.legacy_macros.clone()
    }
}

impl PerNs {
    pub(crate) fn from_def(def: ModuleDefId, v: Visibility, has_constructor: bool) -> PerNs {
        match def {
            ModuleDefId::ModuleId(_) => PerNs::types(def, v),
            ModuleDefId::FunctionId(_) => PerNs::values(def, v),
            ModuleDefId::AdtId(adt) => match adt {
                AdtId::UnionId(_) => PerNs::types(def, v),
                AdtId::EnumId(_) => PerNs::types(def, v),
                AdtId::StructId(_) => {
                    if has_constructor {
                        PerNs::both(def, def, v)
                    } else {
                        PerNs::types(def, v)
                    }
                }
            },
            ModuleDefId::EnumVariantId(_) => PerNs::both(def, def, v),
            ModuleDefId::ConstId(_) | ModuleDefId::StaticId(_) => PerNs::values(def, v),
            ModuleDefId::TraitId(_) => PerNs::types(def, v),
            ModuleDefId::TypeAliasId(_) => PerNs::types(def, v),
            ModuleDefId::BuiltinType(_) => PerNs::types(def, v),
        }
    }
}

#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
pub enum ItemInNs {
    Types(ModuleDefId),
    Values(ModuleDefId),
    Macros(MacroDefId),
}

impl ItemInNs {
    fn match_with(self, per_ns: PerNs) -> Option<Visibility> {
        match self {
            ItemInNs::Types(def) => {
                per_ns.types.filter(|(other_def, _)| *other_def == def).map(|(_, vis)| vis)
            }
            ItemInNs::Values(def) => {
                per_ns.values.filter(|(other_def, _)| *other_def == def).map(|(_, vis)| vis)
            }
            ItemInNs::Macros(def) => {
                per_ns.macros.filter(|(other_def, _)| *other_def == def).map(|(_, vis)| vis)
            }
        }
    }

    pub fn as_module_def_id(self) -> Option<ModuleDefId> {
        match self {
            ItemInNs::Types(id) | ItemInNs::Values(id) => Some(id),
            ItemInNs::Macros(_) => None,
        }
    }

    /// Returns the crate defining this item (or `None` if `self` is built-in).
    pub fn krate(&self, db: &dyn DefDatabase) -> Option<CrateId> {
        Some(match self {
            ItemInNs::Types(did) | ItemInNs::Values(did) => match did {
                ModuleDefId::ModuleId(id) => id.krate,
                ModuleDefId::FunctionId(id) => id.lookup(db).module(db).krate,
                ModuleDefId::AdtId(id) => id.module(db).krate,
                ModuleDefId::EnumVariantId(id) => id.parent.lookup(db).container.module(db).krate,
                ModuleDefId::ConstId(id) => id.lookup(db).container.module(db).krate,
                ModuleDefId::StaticId(id) => id.lookup(db).container.module(db).krate,
                ModuleDefId::TraitId(id) => id.lookup(db).container.module(db).krate,
                ModuleDefId::TypeAliasId(id) => id.lookup(db).module(db).krate,
                ModuleDefId::BuiltinType(_) => return None,
            },
            ItemInNs::Macros(id) => return id.krate,
        })
    }
}
<commit_msg>Simplify entry API usage<commit_after>//! Describes items defined or visible (ie, imported) in a certain scope.
//! This is shared between modules and blocks.

use std::collections::hash_map::Entry;

use hir_expand::name::Name;
use once_cell::sync::Lazy;
use ra_db::CrateId;
use rustc_hash::{FxHashMap, FxHashSet};
use test_utils::mark;

use crate::{
    db::DefDatabase, per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType, HasModule, ImplId,
    LocalModuleId, Lookup, MacroDefId, ModuleDefId, TraitId,
};

#[derive(Copy, Clone)]
pub(crate) enum ImportType {
    Glob,
    Named,
}

#[derive(Debug, Default)]
pub struct PerNsGlobImports {
    types: FxHashSet<(LocalModuleId, Name)>,
    values: FxHashSet<(LocalModuleId, Name)>,
    macros: FxHashSet<(LocalModuleId, Name)>,
}

#[derive(Debug, Default, PartialEq, Eq)]
pub struct ItemScope {
    types: FxHashMap<Name, (ModuleDefId, Visibility)>,
    values: FxHashMap<Name, (ModuleDefId, Visibility)>,
    macros: FxHashMap<Name, (MacroDefId, Visibility)>,
    unresolved: FxHashSet<Name>,

    defs: Vec<ModuleDefId>,
    impls: Vec<ImplId>,
    /// Macros visible in current module in legacy textual scope
    ///
    /// For macros invoked by an unqualified identifier like `bar!()`, `legacy_macros` will be searched in first.
    /// If it yields no result, then it turns to module scoped `macros`.
    /// It macros with name qualified with a path like `crate::foo::bar!()`, `legacy_macros` will be skipped,
    /// and only normal scoped `macros` will be searched in.
    ///
    /// Note that this automatically inherit macros defined textually before the definition of module itself.
    ///
    /// Module scoped macros will be inserted into `items` instead of here.
    // FIXME: Macro shadowing in one module is not properly handled. Non-item place macros will
    // be all resolved to the last one defined if shadowing happens.
    legacy_macros: FxHashMap<Name, MacroDefId>,
}

pub(crate) static BUILTIN_SCOPE: Lazy<FxHashMap<Name, PerNs>> = Lazy::new(|| {
    BuiltinType::ALL
        .iter()
        .map(|(name, ty)| (name.clone(), PerNs::types(ty.clone().into(), Visibility::Public)))
        .collect()
});

/// Shadow mode for builtin type which can be shadowed by module.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub(crate) enum BuiltinShadowMode {
    /// Prefer user-defined modules (or other types) over builtins.
    Module,
    /// Prefer builtins over user-defined modules (but not other types).
    Other,
}

/// Legacy macros can only be accessed through special methods like `get_legacy_macros`.
/// Other methods will only resolve values, types and module scoped macros only.
impl ItemScope {
    pub fn entries<'a>(&'a self) -> impl Iterator<Item = (&'a Name, PerNs)> + 'a {
        // FIXME: shadowing
        let keys: FxHashSet<_> = self
            .types
            .keys()
            .chain(self.values.keys())
            .chain(self.macros.keys())
            .chain(self.unresolved.iter())
            .collect();

        keys.into_iter().map(move |name| (name, self.get(name)))
    }

    pub fn entries_without_primitives<'a>(
        &'a self,
    ) -> impl Iterator<Item = (&'a Name, PerNs)> + 'a {
        self.entries()
    }

    pub fn declarations(&self) -> impl Iterator<Item = ModuleDefId> + '_ {
        self.defs.iter().copied()
    }

    pub fn impls(&self) -> impl Iterator<Item = ImplId> + ExactSizeIterator + '_ {
        self.impls.iter().copied()
    }

    pub fn visibility_of(&self, def: ModuleDefId) -> Option<Visibility> {
        self.name_of(ItemInNs::Types(def))
            .or_else(|| self.name_of(ItemInNs::Values(def)))
            .map(|(_, v)| v)
    }

    /// Iterate over all module scoped macros
    pub(crate) fn macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroDefId)> + 'a {
        self.entries().filter_map(|(name, def)| def.take_macros().map(|macro_| (name, macro_)))
    }

    /// Iterate over all legacy textual scoped macros visible at the end of the module
    pub(crate) fn legacy_macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroDefId)> + 'a {
        self.legacy_macros.iter().map(|(name, def)| (name, *def))
    }

    /// Get a name from current module scope, legacy macros are not included
    pub(crate) fn get(&self, name: &Name) -> PerNs {
        PerNs {
            types: self.types.get(name).copied(),
            values: self.values.get(name).copied(),
            macros: self.macros.get(name).copied(),
        }
    }

    pub(crate) fn name_of(&self, item: ItemInNs) -> Option<(&Name, Visibility)> {
        for (name, per_ns) in self.entries() {
            if let Some(vis) = item.match_with(per_ns) {
                return Some((name, vis));
            }
        }
        None
    }

    pub(crate) fn traits<'a>(&'a self) -> impl Iterator<Item = TraitId> + 'a {
        self.types.values().filter_map(|(def, _)| match def {
            ModuleDefId::TraitId(t) => Some(*t),
            _ => None,
        })
    }

    pub(crate) fn define_def(&mut self, def: ModuleDefId) {
        self.defs.push(def)
    }

    pub(crate) fn get_legacy_macro(&self, name: &Name) -> Option<MacroDefId> {
        self.legacy_macros.get(name).copied()
    }

    pub(crate) fn define_impl(&mut self, imp: ImplId) {
        self.impls.push(imp)
    }

    pub(crate) fn define_legacy_macro(&mut self, name: Name, mac: MacroDefId) {
        self.legacy_macros.insert(name, mac);
    }

    pub(crate) fn push_res(&mut self, name: Name, def: PerNs) -> bool {
        let mut changed = false;

        if let Some(types) = def.types {
            self.types.entry(name.clone()).or_insert_with(|| {
                changed = true;
                types
            });
        }
        if let Some(values) = def.values {
            self.values.entry(name.clone()).or_insert_with(|| {
                changed = true;
                values
            });
        }
        if let Some(macros) = def.macros {
            self.macros.entry(name.clone()).or_insert_with(|| {
                changed = true;
                macros
            });
        }

        if def.is_none() {
            if self.unresolved.insert(name) {
                changed = true;
            }
        }

        changed
    }

    pub(crate) fn push_res_with_import(
        &mut self,
        glob_imports: &mut PerNsGlobImports,
        lookup: (LocalModuleId, Name),
        def: PerNs,
        def_import_type: ImportType,
    ) -> bool {
        let mut changed = false;

        macro_rules! check_changed {
            (
                $changed:ident,
                ( $this:ident / $def:ident ) . $field:ident,
                $glob_imports:ident [ $lookup:ident ],
                $def_import_type:ident
            ) => {{
                let existing = $this.$field.entry($lookup.1.clone());
                match (existing, $def.$field) {
                    (Entry::Vacant(entry), Some(_)) => {
                        match $def_import_type {
                            ImportType::Glob => {
                                $glob_imports.$field.insert($lookup.clone());
                            }
                            ImportType::Named => {
                                $glob_imports.$field.remove(&$lookup);
                            }
                        }

                        if let Some(fld) = $def.$field {
                            entry.insert(fld);
                        }
                        $changed = true;
                    }
                    (Entry::Occupied(mut entry), Some(_))
                        if $glob_imports.$field.contains(&$lookup)
                            && matches!($def_import_type, ImportType::Named) =>
                    {
                        mark::hit!(import_shadowed);
                        $glob_imports.$field.remove(&$lookup);
                        if let Some(fld) = $def.$field {
                            entry.insert(fld);
                        }
                        $changed = true;
                    }
                    _ => {}
                }
            }};
        }

        check_changed!(changed, (self / def).types, glob_imports[lookup], def_import_type);
        check_changed!(changed, (self / def).values, glob_imports[lookup], def_import_type);
        check_changed!(changed, (self / def).macros, glob_imports[lookup], def_import_type);

        if def.is_none() {
            if self.unresolved.insert(lookup.1) {
                changed = true;
            }
        }

        changed
    }

    pub(crate) fn resolutions<'a>(&'a self) -> impl Iterator<Item = (Name, PerNs)> + 'a {
        self.entries().map(|(name, res)| (name.clone(), res))
    }

    pub(crate) fn collect_legacy_macros(&self) -> FxHashMap<Name, MacroDefId> {
        self.legacy_macros.clone()
    }
}

impl PerNs {
    pub(crate) fn from_def(def: ModuleDefId, v: Visibility, has_constructor: bool) -> PerNs {
        match def {
            ModuleDefId::ModuleId(_) => PerNs::types(def, v),
            ModuleDefId::FunctionId(_) => PerNs::values(def, v),
            ModuleDefId::AdtId(adt) => match adt {
                AdtId::UnionId(_) => PerNs::types(def, v),
                AdtId::EnumId(_) => PerNs::types(def, v),
                AdtId::StructId(_) => {
                    if has_constructor {
                        PerNs::both(def, def, v)
                    } else {
                        PerNs::types(def, v)
                    }
                }
            },
            ModuleDefId::EnumVariantId(_) => PerNs::both(def, def, v),
            ModuleDefId::ConstId(_) | ModuleDefId::StaticId(_) => PerNs::values(def, v),
            ModuleDefId::TraitId(_) => PerNs::types(def, v),
            ModuleDefId::TypeAliasId(_) => PerNs::types(def, v),
            ModuleDefId::BuiltinType(_) => PerNs::types(def, v),
        }
    }
}

#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
pub enum ItemInNs {
    Types(ModuleDefId),
    Values(ModuleDefId),
    Macros(MacroDefId),
}

impl ItemInNs {
    fn match_with(self, per_ns: PerNs) -> Option<Visibility> {
        match self {
            ItemInNs::Types(def) => {
                per_ns.types.filter(|(other_def, _)| *other_def == def).map(|(_, vis)| vis)
            }
            ItemInNs::Values(def) => {
                per_ns.values.filter(|(other_def, _)| *other_def == def).map(|(_, vis)| vis)
            }
            ItemInNs::Macros(def) => {
                per_ns.macros.filter(|(other_def, _)| *other_def == def).map(|(_, vis)| vis)
            }
        }
    }

    pub fn as_module_def_id(self) -> Option<ModuleDefId> {
        match self {
            ItemInNs::Types(id) | ItemInNs::Values(id) => Some(id),
            ItemInNs::Macros(_) => None,
        }
    }

    /// Returns the crate defining this item (or `None` if `self` is built-in).
    pub fn krate(&self, db: &dyn DefDatabase) -> Option<CrateId> {
        Some(match self {
            ItemInNs::Types(did) | ItemInNs::Values(did) => match did {
                ModuleDefId::ModuleId(id) => id.krate,
                ModuleDefId::FunctionId(id) => id.lookup(db).module(db).krate,
                ModuleDefId::AdtId(id) => id.module(db).krate,
                ModuleDefId::EnumVariantId(id) => id.parent.lookup(db).container.module(db).krate,
                ModuleDefId::ConstId(id) => id.lookup(db).container.module(db).krate,
                ModuleDefId::StaticId(id) => id.lookup(db).container.module(db).krate,
                ModuleDefId::TraitId(id) => id.lookup(db).container.module(db).krate,
                ModuleDefId::TypeAliasId(id) => id.lookup(db).module(db).krate,
                ModuleDefId::BuiltinType(_) => return None,
            },
            ItemInNs::Macros(id) => return id.krate,
        })
    }
}
<|endoftext|>


<commit_before>use bus::{Addressable, OAM_START, OAM_END, VIDEO_RAM_START, VIDEO_RAM_END};
use enum_primitive::FromPrimitive;

pub const LCD_WIDTH: usize = 160;
pub const LCD_HEIGHT: usize = 144;

const ADDR_LCDC: u16 = 0xFF40;
const ADDR_STAT: u16 = 0xFF41;
const ADDR_SCY: u16  = 0xFF42;
const ADDR_SCX: u16  = 0xFF43;
const ADDR_LY: u16   = 0xFF44;
const ADDR_LYC: u16  = 0xFF45;
const ADDR_DMA: u16  = 0xFF46;
const ADDR_BGP: u16  = 0xFF47;
const ADDR_OBP0: u16 = 0xFF48;
const ADDR_OBP1: u16 = 0xFF49;
const ADDR_WY: u16   = 0xFF4A;
const ADDR_WX: u16   = 0xFF4B;

bitflags! {
    flags Lcdc: u8 {
        const LCDC_ENABLED          = 0b1000_0000,
        const LCDC_TILE_TBL_9C      = 0b0100_0000,
        const LCDC_WIN_ENABLED      = 0b0010_0000,
        const LCDC_SIGNED_TILE_DATA = 0b0001_0000,
        const LCDC_BG_TILE_TBL_9C   = 0b0000_1000,
        const LCDC_16PX_SPRITE      = 0b0000_0100,
        const LCDC_SPRITE_DISPLAY   = 0b0000_0010,
        const LCDC_BG_DISPLAY       = 0b0000_0001
    }
}

// STAT is mostly flags, but the lower 2 bits are the current mode
// Mode is will stored separately so the Stat struct is only treated as bitflags.
bitflags! {
    flags Stat: u8 {
        const STAT_COINCIDENCE_INT   = 0b0100_0000,
        const STAT_OAM_INT           = 0b0010_0000,
        const STAT_VBLANK_INT        = 0b0001_0000,
        const STAT_HBLANK_INT        = 0b0000_1000,
        const STAT_COINCIDENCE_EQUAL = 0b0000_0100
    }
}

enum_from_primitive! {
#[derive(Copy, Clone, PartialEq)]
pub enum Mode {
    VBlank   = 0,
    HBlank   = 1,
    Oam      = 2,
    Transfer = 3
}
}

const CYCLES_PER_OAM_READ: usize = 80;
const CYCLES_PER_TRANSFER: usize = 172;
const CYCLES_PER_HBLANK: usize = 204;
const CYCLES_PER_LINE: usize = 456;

const SHADE_WHITE: u8      = 0;
const SHADE_LIGHT_GRAY: u8 = 1;
const SHADE_DARK_GRAY: u8  = 2;
const SHADE_BLACK: u8      = 3;

struct Pallete(u8);

impl Pallete {
    fn shade(&self, idx: u8) -> u8 {
        self.0 >> (idx * 2)
    }

    fn set_shade(&mut self, idx: u8, shade: u8) {
        self.0 = self.0 | shade << (idx * 2);
    }
}

#[derive(Default)]
pub struct StepResult {
    pub int_vblank: bool,
    pub int_stat: bool
}

pub struct Lcd {
    vram: Vec<u8>,
    oam: Vec<u8>,
    lcdc: Lcdc,
    stat: Stat,
    scy: u8,
    scx: u8,
    ly: u8,
    lyc: u8,
    bgp: Pallete,
    obp0: Pallete,
    obp1: Pallete,
    wy: u8,
    wx: u8,

    mode: Mode,
    mode_cycles: usize
}

impl Lcd {
    pub fn new() -> Self {
        Lcd {
            vram: vec![0; (VIDEO_RAM_END - VIDEO_RAM_START) as usize + 1],
            oam: vec![0; (OAM_END - OAM_START) as usize + 1],
            lcdc: Lcdc::empty(),
            stat: Stat::empty(),
            scy: 0,
            scx: 0,
            ly: 0,
            lyc: 0,
            bgp: Pallete(0),
            obp0: Pallete(0),
            obp1: Pallete(0),
            wy: 0,
            wx: 0,
            mode: Mode::Oam,
            mode_cycles: 0
        }
    }

    pub fn step(&mut self, cycles: usize) -> StepResult {
        let mut result = StepResult::default();
        let previous_mode = self.mode;

        self.mode_cycles = self.mode_cycles + cycles;

        // Current mode is stored in the lower two bits of the STAT register
        match self.mode {
            Mode::Oam => {
                // Process starts with the LCD controller reading information from OAM.
                // This lasts 77-83 cycles
                if self.mode_cycles >= CYCLES_PER_OAM_READ {
                    // Move onto transfer stage
                    self.mode = Mode::Transfer;
                    self.mode_cycles = 0;
                }
            },
            Mode::Transfer => {
                // Data is being actively read by the LCD driver from OAM & VRAM.
                // This lasts 169-175 cycles
                if self.mode_cycles >= CYCLES_PER_TRANSFER {
                    // Once transfer is complete, enter HBLANK
                    self.mode = Mode::HBlank;
                    self.mode_cycles = 0;
                }
            },
            Mode::HBlank => {
                // LCD has reached the end of a line.
                // HBlank phase lasts 201-207 cycles
                if self.mode_cycles >= CYCLES_PER_HBLANK {
                    // LCD is ready to begin the next line
                    self.ly = self.ly + 1;
                    self.mode_cycles = 0;

                    // If the LCD has line 144, then enter VBLANK. Else, enter OAM read.
                    if self.ly == 144 {
                        self.mode = Mode::VBlank;
                        result.int_vblank = true;
                    } else {
                        self.mode = Mode::Oam;
                    };
                }
            },
            Mode::VBlank => {
                // LCD is writing to VBlank lines
                if self.mode_cycles >= CYCLES_PER_LINE {
                    self.mode_cycles = 0;
                    self.ly = self.ly + 1;

                    if self.ly > 153 {
                        // Finished with VBlank. Enter OAM with the first line.
                        self.ly = 0;
                        self.mode = Mode::Oam;
                    }
                }
            }
        }

        // Check if a new mode has been entered during this step.
        // If so, an interrupt will be raised if the respective flag is set in the STAT register
        if self.mode != previous_mode {
            let flag = match self.mode {
                Mode::VBlank   => Some(STAT_VBLANK_INT),
                Mode::HBlank   => Some(STAT_HBLANK_INT),
                Mode::Oam      => Some(STAT_OAM_INT),
                Mode::Transfer => None
            };

            if flag.is_some() && self.stat.contains(flag.unwrap()) {
                result.int_stat = true;
            }
        }

        result

    }
}

impl Addressable for Lcd {
    fn read(&self, addr: u16) -> u8 {
        match addr {
            VIDEO_RAM_START...VIDEO_RAM_END => self.vram[(addr - VIDEO_RAM_START) as usize],
            OAM_START...OAM_END => self.oam[(addr - OAM_START) as usize],
            ADDR_LCDC => self.lcdc.bits,
            ADDR_STAT => (self.stat.bits & 0b1111_1100) | (self.mode as u8),
            ADDR_SCY => self.scy,
            ADDR_SCX => self.scx,
            ADDR_LY => self.ly,
            ADDR_LYC => self.lyc,
            ADDR_BGP => self.bgp.0,
            ADDR_OBP0 => self.obp0.0,
            ADDR_OBP1 => self.obp1.0,
            ADDR_WY => self.wy,
            ADDR_WX => self.wx,
            _ => { println!("LCD IO read unimplemented ({:#X})", addr); 0 }
        }
    }

    fn write(&mut self, addr: u16, val: u8) {
        match addr {
            VIDEO_RAM_START...VIDEO_RAM_END => self.vram[(addr - VIDEO_RAM_START) as usize] = val,
            OAM_START...OAM_END => self.oam[(addr - OAM_START) as usize] = val,
            ADDR_LCDC => self.lcdc.bits = val,
            ADDR_STAT => {
                self.stat.bits = val & 0b1111_1100;
                self.mode = Mode::from_u8(val & 0b11).unwrap();
            },
            ADDR_SCY => self.scy = val,
            ADDR_SCX => self.scx = val,
            //ADDR_LY => self.ly = val,
            ADDR_LYC => self.lyc = val,
            ADDR_DMA => println!("DMA unimplemented"),
            ADDR_BGP => self.bgp = Pallete(val),
            ADDR_OBP0 => self.obp0 = Pallete(val),
            ADDR_OBP1 => self.obp1 = Pallete(val),
            ADDR_WY => self.wy = val,
            ADDR_WX => self.wx = val,
            _ => println!("LCD IO write unimplemented {:#X} -> {:#X}", val, addr)
        }
    }
}<commit_msg>LCD defaults<commit_after>use bus::{Addressable, OAM_START, OAM_END, VIDEO_RAM_START, VIDEO_RAM_END};
use enum_primitive::FromPrimitive;

pub const LCD_WIDTH: usize = 160;
pub const LCD_HEIGHT: usize = 144;

const ADDR_LCDC: u16 = 0xFF40;
const ADDR_STAT: u16 = 0xFF41;
const ADDR_SCY: u16  = 0xFF42;
const ADDR_SCX: u16  = 0xFF43;
const ADDR_LY: u16   = 0xFF44;
const ADDR_LYC: u16  = 0xFF45;
const ADDR_DMA: u16  = 0xFF46;
const ADDR_BGP: u16  = 0xFF47;
const ADDR_OBP0: u16 = 0xFF48;
const ADDR_OBP1: u16 = 0xFF49;
const ADDR_WY: u16   = 0xFF4A;
const ADDR_WX: u16   = 0xFF4B;

bitflags! {
    flags Lcdc: u8 {
        const LCDC_ENABLED          = 0b1000_0000,
        const LCDC_TILE_TBL_9C      = 0b0100_0000,
        const LCDC_WIN_ENABLED      = 0b0010_0000,
        const LCDC_SIGNED_TILE_DATA = 0b0001_0000,
        const LCDC_BG_TILE_TBL_9C   = 0b0000_1000,
        const LCDC_16PX_SPRITE      = 0b0000_0100,
        const LCDC_SPRITE_DISPLAY   = 0b0000_0010,
        const LCDC_BG_DISPLAY       = 0b0000_0001
    }
}

// STAT is mostly flags, but the lower 2 bits are the current mode
// Mode is will stored separately so the Stat struct is only treated as bitflags.
bitflags! {
    flags Stat: u8 {
        const STAT_COINCIDENCE_INT   = 0b0100_0000,
        const STAT_OAM_INT           = 0b0010_0000,
        const STAT_VBLANK_INT        = 0b0001_0000,
        const STAT_HBLANK_INT        = 0b0000_1000,
        const STAT_COINCIDENCE_EQUAL = 0b0000_0100
    }
}

enum_from_primitive! {
#[derive(Copy, Clone, PartialEq)]
pub enum Mode {
    VBlank   = 0,
    HBlank   = 1,
    Oam      = 2,
    Transfer = 3
}
}

const CYCLES_PER_OAM_READ: usize = 80;
const CYCLES_PER_TRANSFER: usize = 172;
const CYCLES_PER_HBLANK: usize = 204;
const CYCLES_PER_LINE: usize = 456;

const SHADE_WHITE: u8      = 0;
const SHADE_LIGHT_GRAY: u8 = 1;
const SHADE_DARK_GRAY: u8  = 2;
const SHADE_BLACK: u8      = 3;

struct Pallete(u8);

impl Pallete {
    fn shade(&self, idx: u8) -> u8 {
        self.0 >> (idx * 2)
    }

    fn set_shade(&mut self, idx: u8, shade: u8) {
        self.0 = self.0 | shade << (idx * 2);
    }
}

#[derive(Default)]
pub struct StepResult {
    pub int_vblank: bool,
    pub int_stat: bool
}

pub struct Lcd {
    vram: Vec<u8>,
    oam: Vec<u8>,
    lcdc: Lcdc,
    stat: Stat,
    scy: u8,
    scx: u8,
    ly: u8,
    lyc: u8,
    bgp: Pallete,
    obp0: Pallete,
    obp1: Pallete,
    wy: u8,
    wx: u8,

    mode: Mode,
    mode_cycles: usize
}

impl Lcd {
    pub fn new() -> Self {
        Lcd {
            vram: vec![0; (VIDEO_RAM_END - VIDEO_RAM_START) as usize + 1],
            oam: vec![0; (OAM_END - OAM_START) as usize + 1],
            lcdc: Lcdc::from_bits(0x91).unwrap(),
            stat: Stat::empty(),
            scy: 0,
            scx: 0,
            ly: 0,
            lyc: 0,
            bgp: Pallete(0xFC),
            obp0: Pallete(0xFF),
            obp1: Pallete(0xFF),
            wy: 0,
            wx: 0,
            mode: Mode::Oam,
            mode_cycles: 0
        }
    }

    pub fn step(&mut self, cycles: usize) -> StepResult {
        let mut result = StepResult::default();
        let previous_mode = self.mode;

        self.mode_cycles = self.mode_cycles + cycles;

        // Current mode is stored in the lower two bits of the STAT register
        match self.mode {
            Mode::Oam => {
                // Process starts with the LCD controller reading information from OAM.
                // This lasts 77-83 cycles
                if self.mode_cycles >= CYCLES_PER_OAM_READ {
                    // Move onto transfer stage
                    self.mode = Mode::Transfer;
                    self.mode_cycles = 0;
                }
            },
            Mode::Transfer => {
                // Data is being actively read by the LCD driver from OAM & VRAM.
                // This lasts 169-175 cycles
                if self.mode_cycles >= CYCLES_PER_TRANSFER {
                    // Once transfer is complete, enter HBLANK
                    self.mode = Mode::HBlank;
                    self.mode_cycles = 0;
                }
            },
            Mode::HBlank => {
                // LCD has reached the end of a line.
                // HBlank phase lasts 201-207 cycles
                if self.mode_cycles >= CYCLES_PER_HBLANK {
                    // LCD is ready to begin the next line
                    self.ly = self.ly + 1;
                    self.mode_cycles = 0;

                    // If the LCD has line 144, then enter VBLANK. Else, enter OAM read.
                    if self.ly == 144 {
                        self.mode = Mode::VBlank;
                        result.int_vblank = true;
                    } else {
                        self.mode = Mode::Oam;
                    };
                }
            },
            Mode::VBlank => {
                // LCD is writing to VBlank lines
                if self.mode_cycles >= CYCLES_PER_LINE {
                    self.mode_cycles = 0;
                    self.ly = self.ly + 1;

                    if self.ly > 153 {
                        // Finished with VBlank. Enter OAM with the first line.
                        self.ly = 0;
                        self.mode = Mode::Oam;
                    }
                }
            }
        }

        // Check if a new mode has been entered during this step.
        // If so, an interrupt will be raised if the respective flag is set in the STAT register
        if self.mode != previous_mode {
            let flag = match self.mode {
                Mode::VBlank   => Some(STAT_VBLANK_INT),
                Mode::HBlank   => Some(STAT_HBLANK_INT),
                Mode::Oam      => Some(STAT_OAM_INT),
                Mode::Transfer => None
            };

            if flag.is_some() && self.stat.contains(flag.unwrap()) {
                result.int_stat = true;
            }
        }

        result

    }
}

impl Addressable for Lcd {
    fn read(&self, addr: u16) -> u8 {
        match addr {
            VIDEO_RAM_START...VIDEO_RAM_END => self.vram[(addr - VIDEO_RAM_START) as usize],
            OAM_START...OAM_END => self.oam[(addr - OAM_START) as usize],
            ADDR_LCDC => self.lcdc.bits,
            ADDR_STAT => (self.stat.bits & 0b1111_1100) | (self.mode as u8),
            ADDR_SCY => self.scy,
            ADDR_SCX => self.scx,
            ADDR_LY => self.ly,
            ADDR_LYC => self.lyc,
            ADDR_BGP => self.bgp.0,
            ADDR_OBP0 => self.obp0.0,
            ADDR_OBP1 => self.obp1.0,
            ADDR_WY => self.wy,
            ADDR_WX => self.wx,
            _ => { println!("LCD IO read unimplemented ({:#X})", addr); 0 }
        }
    }

    fn write(&mut self, addr: u16, val: u8) {
        match addr {
            VIDEO_RAM_START...VIDEO_RAM_END => self.vram[(addr - VIDEO_RAM_START) as usize] = val,
            OAM_START...OAM_END => self.oam[(addr - OAM_START) as usize] = val,
            ADDR_LCDC => self.lcdc.bits = val,
            ADDR_STAT => {
                self.stat.bits = val & 0b1111_1100;
                self.mode = Mode::from_u8(val & 0b11).unwrap();
            },
            ADDR_SCY => self.scy = val,
            ADDR_SCX => self.scx = val,
            //ADDR_LY => self.ly = val,
            ADDR_LYC => self.lyc = val,
            ADDR_DMA => println!("DMA unimplemented"),
            ADDR_BGP => self.bgp = Pallete(val),
            ADDR_OBP0 => self.obp0 = Pallete(val),
            ADDR_OBP1 => self.obp1 = Pallete(val),
            ADDR_WY => self.wy = val,
            ADDR_WX => self.wx = val,
            _ => println!("LCD IO write unimplemented {:#X} -> {:#X}", val, addr)
        }
    }
}<|endoftext|>


<commit_before>#![feature(plugin_registrar, rustc_private, libc)]

extern crate libc;
extern crate rustc;
extern crate syntax;

use rustc::plugin::Registry;
use std::ffi::{CStr, CString};
use std::mem;
use std::str;
use syntax::ast::{TokenTree, ExprLit, LitStr, Expr, Ident};
use syntax::codemap::Span;
use syntax::ext::base::{ExtCtxt, MacResult, MacEager, DummyResult};
use syntax::ext::build::AstBuilder;
use syntax::fold::Folder;
use syntax::parse::token;
use syntax::parse::token::{InternedString, Comma, Eof};
use syntax::parse;
use syntax::parse::parser::Parser;
use syntax::ptr::P;

mod ffi {
    use libc::{c_char, c_int};

    #[repr(C)]
    pub struct ParseResult {
        pub success: c_int,
        pub error_message: *const c_char,
        pub index: c_int,
        pub num_params: c_int,
    }

    extern {
        pub fn init_parser();
        pub fn parse_query(query: *const c_char, result: *mut ParseResult);
    }
}

struct ParseInfo {
    num_params: Option<usize>,
}

struct ParseError {
    message: String,
    index: usize,
}

#[plugin_registrar]
#[doc(hidden)]
pub fn registrar(reg: &mut Registry) {
    reg.register_macro("sql", expand_sql);
    reg.register_macro("execute", expand_execute);
    unsafe { ffi::init_parser() }
}

fn expand_sql(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree])
              -> Box<MacResult+'static> {
    let mut parser = parse::new_parser_from_tts(cx.parse_sess(), cx.cfg(),
                                                tts.to_vec());

    let query_expr = cx.expander().fold_expr(parser.parse_expr_panic());
    let query = match parse_str_lit(cx, &*query_expr) {
        Some(query) => query,
        None => return DummyResult::expr(sp)
    };

    match parse(&query) {
        Ok(_) => {}
        Err(err) => parse_error(cx, query_expr.span, err),
    }

    MacEager::expr(query_expr)
}

fn expand_execute(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree])
                  -> Box<MacResult+'static> {
    let mut parser = parse::new_parser_from_tts(cx.parse_sess(), cx.cfg(),
                                                tts.to_vec());

    let conn = parser.parse_expr_panic();

    if !parser.eat(&Comma).ok().unwrap() {
        cx.span_err(parser.span, "expected `,`");
        return DummyResult::expr(sp);
    }

    let query_expr = cx.expander().fold_expr(parser.parse_expr_panic());
    let query = match parse_str_lit(cx, &*query_expr) {
        Some(query) => query,
        None => return DummyResult::expr(sp),
    };

    if parser.token != Eof && !parser.eat(&Comma).ok().unwrap() {
        cx.span_err(parser.span, "expected `,`");
        return DummyResult::expr(sp);
    }

    let args = match parse_args(cx, &mut parser) {
        Some(args) => args,
        None => return DummyResult::expr(sp),
    };

    match parse(&query) {
        Ok(ParseInfo { num_params: None }) => {
            cx.span_warn(sp, "unable to verify the number of query parameters");
        }
        Ok(ParseInfo { num_params: Some(num_params) }) if num_params != args.len() => {
            cx.span_err(sp, &format!("Expected {} query parameters but got {}",
                                     num_params, args.len()));
        }
        Ok(_) => {}
        Err(err) => parse_error(cx, query_expr.span, err),
    }

    let ident = Ident::with_empty_ctxt(token::intern("execute"));
    let args = cx.expr_vec(sp, args);
    let args = cx.expr_addr_of(sp, args);
    MacEager::expr(cx.expr_method_call(sp, conn, ident, vec![query_expr, args]))
}

fn parse_error(cx: &mut ExtCtxt, sp: Span, err: ParseError) {
    cx.span_err(sp, &format!("Invalid syntax at position {}: {}", err.index, err.message));
}

fn parse_str_lit(cx: &mut ExtCtxt, e: &Expr) -> Option<InternedString> {
    match e.node {
        ExprLit(ref lit) => {
            match lit.node {
                LitStr(ref s, _) => Some(s.clone()),
                _ => {
                    cx.span_err(e.span, "expected string literal");
                    None
                }
            }
        }
        _ => {
            cx.span_err(e.span, "expected string literal");
            None
        }
    }
}

fn parse_args(cx: &mut ExtCtxt, parser: &mut Parser) -> Option<Vec<P<Expr>>> {
    let mut args = Vec::new();

    while parser.token != Eof {
        args.push(parser.parse_expr_panic());

        if !parser.eat(&Comma).ok().unwrap() && parser.token != Eof {
            cx.span_err(parser.span, "expected `,`");
            return None;
        }
    }

    Some(args)
}

fn parse(query: &str) -> Result<ParseInfo, ParseError> {
    unsafe {
        let mut result = mem::uninitialized();
        let query = CString::new(query.as_bytes()).unwrap();
        ffi::parse_query(query.as_ptr(), &mut result);
        if result.success != 0 {
            let num_params = if result.num_params < 0 {
                None
            } else {
                Some(result.num_params as usize)
            };
            Ok(ParseInfo {
                num_params: num_params,
            })
        } else {
            let bytes = CStr::from_ptr(result.error_message).to_bytes();
            Err(ParseError {
                message: str::from_utf8(bytes).unwrap().to_string(),
                index: result.index as usize,
            })
        }
    }
}
<commit_msg>Replace parse_expr_panic() as per breaking changes in rust-lang/rust#44d8abcc0f372dbc7ad58f312303d2e59612dec9.<commit_after>#![feature(plugin_registrar, rustc_private, libc)]

extern crate libc;
extern crate rustc;
extern crate syntax;

use rustc::plugin::Registry;
use std::ffi::{CStr, CString};
use std::mem;
use std::str;
use syntax::ast::{TokenTree, ExprLit, LitStr, Expr, Ident};
use syntax::codemap::Span;
use syntax::ext::base::{ExtCtxt, MacResult, MacEager, DummyResult};
use syntax::ext::build::AstBuilder;
use syntax::fold::Folder;
use syntax::parse::token;
use syntax::parse::token::{InternedString, Comma, Eof};
use syntax::parse;
use syntax::parse::parser::Parser;
use syntax::ptr::P;

mod ffi {
    use libc::{c_char, c_int};

    #[repr(C)]
    pub struct ParseResult {
        pub success: c_int,
        pub error_message: *const c_char,
        pub index: c_int,
        pub num_params: c_int,
    }

    extern {
        pub fn init_parser();
        pub fn parse_query(query: *const c_char, result: *mut ParseResult);
    }
}

struct ParseInfo {
    num_params: Option<usize>,
}

struct ParseError {
    message: String,
    index: usize,
}

#[plugin_registrar]
#[doc(hidden)]
pub fn registrar(reg: &mut Registry) {
    reg.register_macro("sql", expand_sql);
    reg.register_macro("execute", expand_execute);
    unsafe { ffi::init_parser() }
}

fn expand_sql(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree])
              -> Box<MacResult+'static> {
    let mut parser = parse::new_parser_from_tts(cx.parse_sess(), cx.cfg(),
                                                tts.to_vec());

    let query_expr = cx.expander().fold_expr(parser.parse_expr().unwrap());
    let query = match parse_str_lit(cx, &*query_expr) {
        Some(query) => query,
        None => return DummyResult::expr(sp)
    };

    match parse(&query) {
        Ok(_) => {}
        Err(err) => parse_error(cx, query_expr.span, err),
    }

    MacEager::expr(query_expr)
}

fn expand_execute(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree])
                  -> Box<MacResult+'static> {
    let mut parser = parse::new_parser_from_tts(cx.parse_sess(), cx.cfg(),
                                                tts.to_vec());

    let conn = parser.parse_expr().unwrap();

    if !parser.eat(&Comma).ok().unwrap() {
        cx.span_err(parser.span, "expected `,`");
        return DummyResult::expr(sp);
    }

    let query_expr = cx.expander().fold_expr(parser.parse_expr().unwrap());
    let query = match parse_str_lit(cx, &*query_expr) {
        Some(query) => query,
        None => return DummyResult::expr(sp),
    };

    if parser.token != Eof && !parser.eat(&Comma).ok().unwrap() {
        cx.span_err(parser.span, "expected `,`");
        return DummyResult::expr(sp);
    }

    let args = match parse_args(cx, &mut parser) {
        Some(args) => args,
        None => return DummyResult::expr(sp),
    };

    match parse(&query) {
        Ok(ParseInfo { num_params: None }) => {
            cx.span_warn(sp, "unable to verify the number of query parameters");
        }
        Ok(ParseInfo { num_params: Some(num_params) }) if num_params != args.len() => {
            cx.span_err(sp, &format!("Expected {} query parameters but got {}",
                                     num_params, args.len()));
        }
        Ok(_) => {}
        Err(err) => parse_error(cx, query_expr.span, err),
    }

    let ident = Ident::with_empty_ctxt(token::intern("execute"));
    let args = cx.expr_vec(sp, args);
    let args = cx.expr_addr_of(sp, args);
    MacEager::expr(cx.expr_method_call(sp, conn, ident, vec![query_expr, args]))
}

fn parse_error(cx: &mut ExtCtxt, sp: Span, err: ParseError) {
    cx.span_err(sp, &format!("Invalid syntax at position {}: {}", err.index, err.message));
}

fn parse_str_lit(cx: &mut ExtCtxt, e: &Expr) -> Option<InternedString> {
    match e.node {
        ExprLit(ref lit) => {
            match lit.node {
                LitStr(ref s, _) => Some(s.clone()),
                _ => {
                    cx.span_err(e.span, "expected string literal");
                    None
                }
            }
        }
        _ => {
            cx.span_err(e.span, "expected string literal");
            None
        }
    }
}

fn parse_args(cx: &mut ExtCtxt, parser: &mut Parser) -> Option<Vec<P<Expr>>> {
    let mut args = Vec::new();

    while parser.token != Eof {
        args.push(parser.parse_expr().unwrap());

        if !parser.eat(&Comma).ok().unwrap() && parser.token != Eof {
            cx.span_err(parser.span, "expected `,`");
            return None;
        }
    }

    Some(args)
}

fn parse(query: &str) -> Result<ParseInfo, ParseError> {
    unsafe {
        let mut result = mem::uninitialized();
        let query = CString::new(query.as_bytes()).unwrap();
        ffi::parse_query(query.as_ptr(), &mut result);
        if result.success != 0 {
            let num_params = if result.num_params < 0 {
                None
            } else {
                Some(result.num_params as usize)
            };
            Ok(ParseInfo {
                num_params: num_params,
            })
        } else {
            let bytes = CStr::from_ptr(result.error_message).to_bytes();
            Err(ParseError {
                message: str::from_utf8(bytes).unwrap().to_string(),
                index: result.index as usize,
            })
        }
    }
}
<|endoftext|>


<commit_before>/*!
Compile-time dimensional analysis for various unit systems using Rust's type system.

Its goal is to provide zero cost unit safety while requiring minimal effort from the programmer.

For a short introduction and some examples, check out the [readme on
GitHub](https://github.com/paholg/dimensioned).

# Use

The recommended way to import this crate is with the rename

```rust
extern crate dimensioned as dim;
```

and then either import the module for the unit system you will be using,

```rust
# extern crate dimensioned as dim;
# fn main() {
use dim::si;
let x = 3.0 * si::M;
# }
```

or import the constants and/or types that you care about,

```rust
# extern crate dimensioned as dim;
# fn main() {
use dim::si::{Meter, M, S};
let x: Meter<f64> = 3.0 * M;
let t = 2.0 * S;
# }
```

For clarity, all the examples contained herein will import unit system modules.

# How it works

When a unit system is created, say the SI system, a struct with two parameters is made; in this
case `SI<V, U>`. The first parameter, `V`, is for the value type -- it can be anything, and is the
value to which we are giving units. The second parameter, `U`, is where the magic happens. It
represents the units, and is a type-level array of type-level numbers. Now, these guys have some
pretty ugly type signatures, so I will express the array as the macro which maps to it, `tarr![]`,
and the type numbers as their aliases; `N1` for -1, `Z0` for 0, `P1` for 1, etc.

The SI system has seven base units, so that's how many elements the type array needs to have. The
order is the order in which the base units were defined, and the values of the type numbers are the
power to which each unit is raised. For example, the first three SI units, in order, are `Meter`,
`Kilogram`, `Second`, so the following aliases exist:

```rust
#[macro_use]
extern crate dimensioned as dim;
use dim::si::SI;
use dim::typenum::{P1, Z0, N1, N2};

type Meter<V>    = SI<V, tarr![P1, Z0, Z0, Z0, Z0, Z0, Z0]>;
type Kilogram<V> = SI<V, tarr![Z0, P1, Z0, Z0, Z0, Z0, Z0]>;
type Second<V>   = SI<V, tarr![Z0, Z0, P1, Z0, Z0, Z0, Z0]>;
type Newton<V>   = SI<V, tarr![P1, P1, N2, Z0, Z0, Z0, Z0]>;
// ...

fn main() {}
```

In addition to creating the unit system struct, `SI`, the type aliases, and constants for each,
various traits are implemented for the unit system. These include arithmetic operations, which work
as follows.

If you try to add a `Meter<f64>` to a `Second<f64>`, then you will get a compiler error because
they have different types and so addition is not defined. Multiplication, on the other hand, is
defined, and results in a normal multiplication of the value types, and the unit powers added.

So, multiplying `Meter<f64>` by `Second<f64>` gives `SI<f64, tarr![P1, Z0, P1, Z0, Z0, Z0,
Z0]>`.

## Example

```rust
extern crate dimensioned as dim;

use dim::si;

fn main() {
    let x = 3.0 * si::M;
    let t = 2.0 * si::S;
    assert_eq!("6 m*s", &format!("{}", x*t));
}
```

That's basically it. All of the dimensional safety comes from whether things typecheck, and from
performing type-level arithmetic, thanks to the [typenum](http://paholg.com/typenum/)
crate. Pretty much everything else is for ergonomics.

*/

#![doc(
    html_logo_url = "https://raw.githubusercontent.com/paholg/dimensioned/master/favicon.png",
    html_favicon_url = "https://raw.githubusercontent.com/paholg/dimensioned/master/favicon.png",
    html_root_url = "http://paholg.com/dimensioned"
)]
#![cfg_attr(not(feature="clapme"), no_std)]
#![warn(missing_docs)]
#![cfg_attr(feature = "oibit", feature(optin_builtin_traits))]
#![cfg_attr(feature = "spec", feature(specialization))]
#![cfg_attr(feature = "clippy", feature(plugin))]
#![cfg_attr(feature = "clippy", plugin(clippy))]
#![allow(unknown_lints)]
#![deny(clippy)]
#![allow(type_complexity, float_cmp, useless_attribute, doc_markdown)]
#![cfg_attr(
    feature = "cargo-clippy", allow(type_complexity, float_cmp, useless_attribute, doc_markdown)
)]

#[cfg(feature="clapme")]
extern crate core;
#[cfg(feature="clapme")]
extern crate clapme;
#[cfg(feature="clapme")]

// Macro debugging
// #![feature(trace_macros)]
// trace_macros!(true);

pub extern crate typenum;

// Copied from typenum so that users don't have to import typenum for the make_units macro to work.
// Only change is the paths.
/// Construct a type-level array of type-level integers
///
/// # Example
/// ```rust
/// #[macro_use]
/// extern crate dimensioned as dim;
/// #[macro_use]
/// extern crate generic_array;
///
/// use dim::typenum::consts::*;
/// type TArr = tarr![P3, P2, N5, N8, P2];
///
/// fn main() {
///     use dim::array::ToGA;
///     let x = TArr::to_ga();
///     let y = arr![isize; 3, 2, -5, -8, 2];
///
///     assert_eq!(x, y);
/// }
/// ```
#[macro_export]
macro_rules! tarr {
    () => ( $crate::typenum::ATerm );
    ($n:ty) => ( $crate::typenum::TArr<$n, $crate::typenum::ATerm> );
    ($n:ty,) => ( $crate::typenum::TArr<$n, $crate::typenum::ATerm> );
    ($n:ty, $($tail:ty),+) => ( $crate::typenum::TArr<$n, tarr![$($tail),+]> );
    ($n:ty, $($tail:ty),+,) => ( $crate::typenum::TArr<$n, tarr![$($tail),+]> );
}

// Get a warning without this. If it's fixed, remove `useless_attribute` from clippy allow list
#[allow(unused_imports)]
#[macro_use]
pub extern crate generic_array;

#[cfg(feature = "approx")]
pub extern crate approx;

#[cfg(feature = "serde")]
pub extern crate serde;
#[cfg(feature = "serde_test")]
extern crate serde_test;

#[macro_use]
mod make_units;
mod fmt;

include!(concat!(env!("OUT_DIR"), "/unit_systems.rs"));
pub mod array;
pub mod conversion;
pub mod dimensions;
pub mod f32prefixes;
pub mod f64prefixes;
pub mod traits;

pub use traits::*;
pub use unit_systems::{cgs, fps, mks, si, ucum};

// Used for the make_units macro
#[doc(hidden)]
pub mod dimcore {
    pub use core::{f32, f64, fmt, marker, mem, ops};
}
<commit_msg>fix bug that broke build when feature clapme was not used<commit_after>/*!
Compile-time dimensional analysis for various unit systems using Rust's type system.

Its goal is to provide zero cost unit safety while requiring minimal effort from the programmer.

For a short introduction and some examples, check out the [readme on
GitHub](https://github.com/paholg/dimensioned).

# Use

The recommended way to import this crate is with the rename

```rust
extern crate dimensioned as dim;
```

and then either import the module for the unit system you will be using,

```rust
# extern crate dimensioned as dim;
# fn main() {
use dim::si;
let x = 3.0 * si::M;
# }
```

or import the constants and/or types that you care about,

```rust
# extern crate dimensioned as dim;
# fn main() {
use dim::si::{Meter, M, S};
let x: Meter<f64> = 3.0 * M;
let t = 2.0 * S;
# }
```

For clarity, all the examples contained herein will import unit system modules.

# How it works

When a unit system is created, say the SI system, a struct with two parameters is made; in this
case `SI<V, U>`. The first parameter, `V`, is for the value type -- it can be anything, and is the
value to which we are giving units. The second parameter, `U`, is where the magic happens. It
represents the units, and is a type-level array of type-level numbers. Now, these guys have some
pretty ugly type signatures, so I will express the array as the macro which maps to it, `tarr![]`,
and the type numbers as their aliases; `N1` for -1, `Z0` for 0, `P1` for 1, etc.

The SI system has seven base units, so that's how many elements the type array needs to have. The
order is the order in which the base units were defined, and the values of the type numbers are the
power to which each unit is raised. For example, the first three SI units, in order, are `Meter`,
`Kilogram`, `Second`, so the following aliases exist:

```rust
#[macro_use]
extern crate dimensioned as dim;
use dim::si::SI;
use dim::typenum::{P1, Z0, N1, N2};

type Meter<V>    = SI<V, tarr![P1, Z0, Z0, Z0, Z0, Z0, Z0]>;
type Kilogram<V> = SI<V, tarr![Z0, P1, Z0, Z0, Z0, Z0, Z0]>;
type Second<V>   = SI<V, tarr![Z0, Z0, P1, Z0, Z0, Z0, Z0]>;
type Newton<V>   = SI<V, tarr![P1, P1, N2, Z0, Z0, Z0, Z0]>;
// ...

fn main() {}
```

In addition to creating the unit system struct, `SI`, the type aliases, and constants for each,
various traits are implemented for the unit system. These include arithmetic operations, which work
as follows.

If you try to add a `Meter<f64>` to a `Second<f64>`, then you will get a compiler error because
they have different types and so addition is not defined. Multiplication, on the other hand, is
defined, and results in a normal multiplication of the value types, and the unit powers added.

So, multiplying `Meter<f64>` by `Second<f64>` gives `SI<f64, tarr![P1, Z0, P1, Z0, Z0, Z0,
Z0]>`.

## Example

```rust
extern crate dimensioned as dim;

use dim::si;

fn main() {
    let x = 3.0 * si::M;
    let t = 2.0 * si::S;
    assert_eq!("6 m*s", &format!("{}", x*t));
}
```

That's basically it. All of the dimensional safety comes from whether things typecheck, and from
performing type-level arithmetic, thanks to the [typenum](http://paholg.com/typenum/)
crate. Pretty much everything else is for ergonomics.

*/

#![doc(
    html_logo_url = "https://raw.githubusercontent.com/paholg/dimensioned/master/favicon.png",
    html_favicon_url = "https://raw.githubusercontent.com/paholg/dimensioned/master/favicon.png",
    html_root_url = "http://paholg.com/dimensioned"
)]
#![cfg_attr(not(feature="clapme"), no_std)]
#![warn(missing_docs)]
#![cfg_attr(feature = "oibit", feature(optin_builtin_traits))]
#![cfg_attr(feature = "spec", feature(specialization))]
#![cfg_attr(feature = "clippy", feature(plugin))]
#![cfg_attr(feature = "clippy", plugin(clippy))]
#![allow(unknown_lints)]
#![deny(clippy)]
#![allow(type_complexity, float_cmp, useless_attribute, doc_markdown)]
#![cfg_attr(
    feature = "cargo-clippy", allow(type_complexity, float_cmp, useless_attribute, doc_markdown)
)]

#[cfg(feature="clapme")]
extern crate core;
#[cfg(feature="clapme")]
extern crate clapme;

// Macro debugging
// #![feature(trace_macros)]
// trace_macros!(true);

pub extern crate typenum;

// Copied from typenum so that users don't have to import typenum for the make_units macro to work.
// Only change is the paths.
/// Construct a type-level array of type-level integers
///
/// # Example
/// ```rust
/// #[macro_use]
/// extern crate dimensioned as dim;
/// #[macro_use]
/// extern crate generic_array;
///
/// use dim::typenum::consts::*;
/// type TArr = tarr![P3, P2, N5, N8, P2];
///
/// fn main() {
///     use dim::array::ToGA;
///     let x = TArr::to_ga();
///     let y = arr![isize; 3, 2, -5, -8, 2];
///
///     assert_eq!(x, y);
/// }
/// ```
#[macro_export]
macro_rules! tarr {
    () => ( $crate::typenum::ATerm );
    ($n:ty) => ( $crate::typenum::TArr<$n, $crate::typenum::ATerm> );
    ($n:ty,) => ( $crate::typenum::TArr<$n, $crate::typenum::ATerm> );
    ($n:ty, $($tail:ty),+) => ( $crate::typenum::TArr<$n, tarr![$($tail),+]> );
    ($n:ty, $($tail:ty),+,) => ( $crate::typenum::TArr<$n, tarr![$($tail),+]> );
}

// Get a warning without this. If it's fixed, remove `useless_attribute` from clippy allow list
#[allow(unused_imports)]
#[macro_use]
pub extern crate generic_array;

#[cfg(feature = "approx")]
pub extern crate approx;

#[cfg(feature = "serde")]
pub extern crate serde;
#[cfg(feature = "serde_test")]
extern crate serde_test;

#[macro_use]
mod make_units;
mod fmt;

include!(concat!(env!("OUT_DIR"), "/unit_systems.rs"));
pub mod array;
pub mod conversion;
pub mod dimensions;
pub mod f32prefixes;
pub mod f64prefixes;
pub mod traits;

pub use traits::*;
pub use unit_systems::{cgs, fps, mks, si, ucum};

// Used for the make_units macro
#[doc(hidden)]
pub mod dimcore {
    pub use core::{f32, f64, fmt, marker, mem, ops};
}
<|endoftext|>


<commit_before>extern crate glutin;
extern crate trdl;

use std::os::raw::c_void;

fn make_shape(off_x: f32, off_y: f32, fill_color: Option<(f32, f32, f32)>,
              stroke_color: (f32, f32, f32), stroke_width: u32) -> trdl::Path {
    trdl::Path::new((500f32, 300f32)).
        arc_to(200f32, 200f32, 0f32, (300f32, 500f32), true, true).
        arc_to(200f32, 200f32, 0f32, (500f32, 300f32), false, true).
        //arc_to(200f32, 200f32, 0f32, (100f32, 300f32), true, true).
        //arc_to(200f32, 200f32, 0f32, (300f32, 100f32), true, true).
        //arc_to(200f32, 200f32, 0f32, (500f32, 300f32), true, true).
        set_stroke(0.1f32, 0.8f32, 0f32, 6)

//    let a0 = (150f32 + off_x, 150f32 + off_y);
//    let b0 = (300f32 + off_x, 200f32 + off_y);
//    let bc1 = (350f32 + off_x, 250f32 + off_y);
//    let bc2 = (200f32 + off_x, 250f32 + off_y);
//    let c0 = (200f32 + off_x, 300f32 + off_y);
//    let d0 = (50f32 + off_x, 100f32 + off_y);
//    let de1 = (0f32 + off_x, 50f32 + off_y);
//    let de2 = (50f32 + off_x, 0f32 + off_y);
//    let e0 = (150f32 + off_x, 0f32 + off_y);
//
//    trdl::Path::with_num_vertices(a0, 5).
//        line_to(b0).
//        curve_to(bc1, bc2, c0).
//        line_to(d0).
//        curve_to(de1, de2, e0).
//        // line_to(a0). // automatic, but allowed
//        close_path().
//        set_stroke(stroke_color.0, stroke_color.1, stroke_color.2, stroke_width)

//    let a = (  0f32 + off_x, 0f32   + off_y);
//    let b = (200f32 + off_x, 0f32   + off_y);
//    let c = (200f32 + off_x, 200f32 + off_y);
//    let d = (  0f32 + off_x, 200f32 + off_y);

//    let path = trdl::Path::with_num_vertices(4).
//        add_straight_line(a).
//        add_straight_line(b).
//        add_straight_line(c).
//        add_straight_line(d).
//        set_stroke(stroke_color.0, stroke_color.1, stroke_color.2, stroke_width);
//    if let Some(fill_color) = fill_color {
//        path.set_fill_color(fill_color.0, fill_color.1, fill_color.2).close_path()
//    } else {
//        path
//    }
}

struct Window {
    w: glutin::Window
}

impl trdl::Window for Window {
    fn set_context(&self) {
        unsafe { self.w.make_current().unwrap() };
    }
    fn load_fn(&self, addr: &str) -> *const c_void {
        self.w.get_proc_address(addr) as *const c_void
    }
 }

fn main() {
    let window_size = (1024, 768);
    let window = Window {
        w: glutin::WindowBuilder::new().
        with_dimensions(window_size.0, window_size.1).
        with_title("TRDL Test").
        build().unwrap() };

    let mut drawing = trdl::Drawing::new(&window, window_size.0, window_size.1,
            0.4, 0.5, 0.6).unwrap();

    let mut idx = 0usize;
    let sqrt_size = 1u32;
    let num_shapes = sqrt_size * sqrt_size;
    let wx = window_size.0 as i32 - 300i32;
    let wy = window_size.1 as i32 - 300i32;

    let colors = [(1.0f32, 0.5f32, 0.0f32), (0.0f32, 0.7f32, 0.4f32),
                  (0.5f32, 0.7f32, 0.3f32), (0.3f32, 0.2f32, 0.9f32)];
    let stroke_colors = [(0.0f32, 0.0f32, 1.0f32), (0.5f32, 0.0f32, 0.2f32),
        (0.0f32, 0.0f32, 0.3f32), (0.3f32, 0.7f32, 0.0f32)];
    let thicknesses = [5, 10, 20, 50];

    let mut do_fill = true;
    for i in 0..sqrt_size {
        let delta_x = 100 + wx * (i as i32) / (sqrt_size as i32);
        for j in 0..sqrt_size {
            let delta_y = 100 + wy * (j as i32) / (sqrt_size as i32);
            let fill_color = if do_fill { Some(colors[idx]) } else { None };
            drawing.add_path
                (make_shape(delta_x as f32, delta_y as f32,
                            fill_color, stroke_colors[idx], thicknesses[idx])).unwrap();
            do_fill = !do_fill;
            idx += 1;
            if idx > 3 { idx = 0; }
        }
    }
    drawing.draw();
    window.w.swap_buffers().unwrap();
    for event in window.w.wait_events() {
        if let glutin::Event::Closed = event {
            break;
        }
    }
}<commit_msg>made the feet (still need the toes)<commit_after>extern crate glutin;
extern crate trdl;

use std::os::raw::c_void;

fn offset(point: (f32, f32), offset: (f32, f32)) -> (f32, f32) {
    (point.0 + offset.0, point.1 + offset.1)
}

fn make_foot(off: (f32, f32), is_right: bool, is_back: bool) -> trdl::Path {
    let mut points = [(0f32, 0f32), (50f32, 50f32), (80f32, 100f32), (100f32, 200f32),
                     (0f32, 250f32), (-75f32, 200f32), (-100f32, 100f32), (0f32, 0f32)];
    let stroke = (0f32, 0f32, 0f32, 6);
    let fill_color = (0f32, 1f32, 0f32);
    let mut backwards = false;
    if is_right {
        if is_back {
            for p in &mut points {
                *p = (-p.0 + off.0, -p.1 + off.1);
            }
        } else {
            for p in &mut points {
                *p = (p.0 + off.0, -p.1 + off.1);
            }
            backwards = true;
        }
    } else {
        if is_back {
            for p in &mut points {
                *p = (-p.0 + off.0, p.1 + off.1);
            }
            backwards = true;
        } else {
            for p in &mut points {
                *p = (p.0 + off.0, p.1 + off.1);
            }
        }
    }
    if backwards {
        trdl::Path::new(points[7]).
            line_to(points[6]).
            curve_to(points[5], points[4], points[3]).
            curve_to(points[2], points[1], points[0]).
            close_path().
            set_stroke(stroke.0, stroke.1, stroke.2, stroke.3).
            set_fill_color(fill_color.0, fill_color.1, fill_color.2)
    } else {
        trdl::Path::new(points[0]).
            curve_to(points[1], points[2], points[3]).
            curve_to(points[4], points[5], points[6]).
            line_to(points[7]).
            close_path().
            set_stroke(stroke.0, stroke.1, stroke.2, stroke.3).
            set_fill_color(fill_color.0, fill_color.1, fill_color.2)
    }
}

fn make_shape(off_x: f32, off_y: f32) -> Vec<trdl::Path> {
    let mut paths = Vec::new();
    paths.push(make_foot((off_x + 200f32, off_y + 100_f32), false, false));
    paths.push(make_foot((off_x + 200f32, off_y - 100_f32), true, false));
    paths.push(make_foot((off_x - 200f32, off_y + 80_f32), false, true));
    paths.push(make_foot((off_x - 200f32, off_y - 80_f32), true, true));
    paths
}

struct Window {
    w: glutin::Window
}

impl trdl::Window for Window {
    fn set_context(&self) {
        unsafe { self.w.make_current().unwrap() };
    }
    fn load_fn(&self, addr: &str) -> *const c_void {
        self.w.get_proc_address(addr) as *const c_void
    }
 }

fn main() {
    let window_size = (1280, 800);
    let window = Window {
        w: glutin::WindowBuilder::new().
        with_dimensions(window_size.0, window_size.1).
        with_title("TRDL Test").
        build().unwrap() };

    let mut drawing = trdl::Drawing::new(&window, window_size.0, window_size.1,
            0.4, 0.5, 0.6).unwrap();

    let mut idx = 0usize;
    let sqrt_size = 1u32;
    let num_shapes = sqrt_size * sqrt_size;
    let wx = window_size.0 as i32 - 300i32;
    let wy = window_size.1 as i32 - 300i32;

    let paths = make_shape(600f32, 400f32);
    for p in paths {
        drawing.add_path(p).unwrap();
    }

    drawing.draw();
    window.w.swap_buffers().unwrap();
    for event in window.w.wait_events() {
        if let glutin::Event::Closed = event {
            break;
        }
    }
}<|endoftext|>


<commit_before>//! jsonrpc http server.
//!
//! ```no_run
//! extern crate jsonrpc_core;
//! extern crate jsonrpc_http_server;
//!
//! use std::sync::Arc;
//! use jsonrpc_core::*;
//! use jsonrpc_http_server::*;
//!
//! struct SayHello;
//! impl MethodCommand for SayHello {
//! 	fn execute(&self, _params: Params) -> Result<Value, Error> {
//! 		Ok(Value::String("hello".to_string()))
//! 	}
//! }
//!
//! fn main() {
//! 	let io = IoHandler::new();
//! 	io.add_method("say_hello", SayHello);
//! 	let _server = Server::start(&"127.0.0.1:3030".parse().unwrap(), Arc::new(io), AccessControlAllowOrigin::Null);
//! }
//! ```

extern crate hyper;
extern crate unicase;
extern crate jsonrpc_core as jsonrpc;

use std::sync::Arc;
use std::io::{Read, Write};
use std::net::SocketAddr;
use hyper::header::{Headers, Allow, ContentType, AccessControlAllowHeaders};
use hyper::method::Method;
use hyper::server::{Request, Response};
use hyper::{Next, Encoder, Decoder};
use hyper::net::HttpStream;
use unicase::UniCase;
use self::jsonrpc::{IoHandler};

pub use hyper::header::AccessControlAllowOrigin;

pub type ServerResult = Result<Server, RpcServerError>;

/// RPC Server startup error
#[derive(Debug)]
pub enum RpcServerError {
	IoError(std::io::Error),
	Other(hyper::error::Error),
}

impl From<hyper::error::Error> for RpcServerError {
	fn from(err: hyper::error::Error) -> Self {
		match err {
			hyper::error::Error::Io(e) => RpcServerError::IoError(e),
			e => RpcServerError::Other(e)
		}
	}
}
/// jsonrpc http request handler.
pub struct ServerHandler {
	jsonrpc_handler: Arc<IoHandler>,
	cors_domain: AccessControlAllowOrigin,
	request: String,
	response: Option<String>,
}

impl ServerHandler {
	/// Create new request handler.
	pub fn new(jsonrpc_handler: Arc<IoHandler>, cors_domain: AccessControlAllowOrigin) -> Self {
		ServerHandler {
			jsonrpc_handler: jsonrpc_handler,
			cors_domain: cors_domain,
			request: String::new(),
			response: None,
		}
	}

	fn response_headers(&self) -> Headers {
		let mut headers = Headers::new();
		headers.set(
			Allow(vec![
				Method::Options, Method::Post
			])
		);
		headers.set(ContentType::json());
		headers.set(
			AccessControlAllowHeaders(vec![
				UniCase("origin".to_owned()),
				UniCase("content-type".to_owned()),
				UniCase("accept".to_owned()),
			])
		);
		headers.set(self.cors_domain.clone());
		headers
	}
}

impl hyper::server::Handler<HttpStream> for ServerHandler {
    fn on_request(&mut self, request: Request) -> Next {
		match *request.method() {
			Method::Options => {
				self.response = Some(String::new());
				Next::write()
			},
			Method::Post => Next::read(),
			_ => Next::write(),
		}
	}

    /// This event occurs each time the `Request` is ready to be read from.
    fn on_request_readable(&mut self, decoder: &mut Decoder<HttpStream>) -> Next {
		match decoder.read_to_string(&mut self.request) {
			Ok(0) => {
				self.response = self.jsonrpc_handler.handle_request(&self.request);
				Next::write()
			}
			Ok(_) => {
				Next::read()
			}
			Err(e) => match e.kind() {
				::std::io::ErrorKind::WouldBlock => Next::read(),
				_ => {
					//trace!("Read error: {}", e);
					Next::end()
				}
			}
		}
	}

    /// This event occurs after the first time this handled signals `Next::write()`.
    fn on_response(&mut self, response: &mut Response) -> Next {
		*response.headers_mut() = self.response_headers();
		if self.response.is_none() {
			response.set_status(hyper::status::StatusCode::MethodNotAllowed);
		}
		Next::write()
	}

    /// This event occurs each time the `Response` is ready to be written to.
    fn on_response_writable(&mut self, encoder: &mut Encoder<HttpStream>) -> Next {
		if let Some(ref response) = self.response {
			encoder.write(response.as_bytes()).unwrap();
		}
		Next::end()
	}
}

/// jsonrpc http server.
///
/// ```no_run
/// extern crate jsonrpc_core;
/// extern crate jsonrpc_http_server;
///
/// use std::sync::Arc;
/// use jsonrpc_core::*;
/// use jsonrpc_http_server::*;
///
/// struct SayHello;
/// impl MethodCommand for SayHello {
/// 	fn execute(&self, _params: Params) -> Result<Value, Error> {
/// 		Ok(Value::String("hello".to_string()))
/// 	}
/// }
///
/// fn main() {
/// 	let io = IoHandler::new();
/// 	io.add_method("say_hello", SayHello);
/// 	let _server = Server::start(&"127.0.0.1:3030".parse().unwrap(), Arc::new(io), AccessControlAllowOrigin::Null);
/// }
/// ```
pub struct Server {
	server: Option<hyper::server::Listening>,
}

impl Server {
	pub fn start(addr: &SocketAddr, jsonrpc_handler: Arc<IoHandler>, cors_domain: AccessControlAllowOrigin) -> ServerResult {
		let srv = try!(try!(hyper::Server::http(addr)).handle(move |_| ServerHandler::new(jsonrpc_handler.clone(), cors_domain.clone())));
		Ok(Server {
			server: Some(srv),
		})
	}
}

impl Drop for Server {
	fn drop(&mut self) {
		self.server.take().unwrap().close()
	}
}
<commit_msg>Chunked writes<commit_after>//! jsonrpc http server.
//!
//! ```no_run
//! extern crate jsonrpc_core;
//! extern crate jsonrpc_http_server;
//!
//! use std::sync::Arc;
//! use jsonrpc_core::*;
//! use jsonrpc_http_server::*;
//!
//! struct SayHello;
//! impl MethodCommand for SayHello {
//! 	fn execute(&self, _params: Params) -> Result<Value, Error> {
//! 		Ok(Value::String("hello".to_string()))
//! 	}
//! }
//!
//! fn main() {
//! 	let io = IoHandler::new();
//! 	io.add_method("say_hello", SayHello);
//! 	let _server = Server::start(&"127.0.0.1:3030".parse().unwrap(), Arc::new(io), AccessControlAllowOrigin::Null);
//! }
//! ```

extern crate hyper;
extern crate unicase;
extern crate jsonrpc_core as jsonrpc;

use std::sync::Arc;
use std::io::{Read, Write};
use std::net::SocketAddr;
use hyper::header::{Headers, Allow, ContentType, AccessControlAllowHeaders};
use hyper::method::Method;
use hyper::server::{Request, Response};
use hyper::{Next, Encoder, Decoder};
use hyper::net::HttpStream;
use unicase::UniCase;
use self::jsonrpc::{IoHandler};

pub use hyper::header::AccessControlAllowOrigin;

pub type ServerResult = Result<Server, RpcServerError>;

/// RPC Server startup error
#[derive(Debug)]
pub enum RpcServerError {
	IoError(std::io::Error),
	Other(hyper::error::Error),
}

impl From<hyper::error::Error> for RpcServerError {
	fn from(err: hyper::error::Error) -> Self {
		match err {
			hyper::error::Error::Io(e) => RpcServerError::IoError(e),
			e => RpcServerError::Other(e)
		}
	}
}
/// jsonrpc http request handler.
pub struct ServerHandler {
	jsonrpc_handler: Arc<IoHandler>,
	cors_domain: AccessControlAllowOrigin,
	request: String,
	response: Option<String>,
	write_pos: usize,
}

impl ServerHandler {
	/// Create new request handler.
	pub fn new(jsonrpc_handler: Arc<IoHandler>, cors_domain: AccessControlAllowOrigin) -> Self {
		ServerHandler {
			jsonrpc_handler: jsonrpc_handler,
			cors_domain: cors_domain,
			request: String::new(),
			response: None,
			write_pos: 0,
		}
	}

	fn response_headers(&self) -> Headers {
		let mut headers = Headers::new();
		headers.set(
			Allow(vec![
				Method::Options, Method::Post
			])
		);
		headers.set(ContentType::json());
		headers.set(
			AccessControlAllowHeaders(vec![
				UniCase("origin".to_owned()),
				UniCase("content-type".to_owned()),
				UniCase("accept".to_owned()),
			])
		);
		headers.set(self.cors_domain.clone());
		headers
	}
}

impl hyper::server::Handler<HttpStream> for ServerHandler {
    fn on_request(&mut self, request: Request) -> Next {
		match *request.method() {
			Method::Options => {
				self.response = Some(String::new());
				Next::write()
			},
			Method::Post => Next::read(),
			_ => Next::write(),
		}
	}

    /// This event occurs each time the `Request` is ready to be read from.
    fn on_request_readable(&mut self, decoder: &mut Decoder<HttpStream>) -> Next {
		match decoder.read_to_string(&mut self.request) {
			Ok(0) => {
				self.response = self.jsonrpc_handler.handle_request(&self.request);
				Next::write()
			}
			Ok(_) => {
				Next::read()
			}
			Err(e) => match e.kind() {
				::std::io::ErrorKind::WouldBlock => Next::read(),
				_ => {
					//trace!("Read error: {}", e);
					Next::end()
				}
			}
		}
	}

    /// This event occurs after the first time this handled signals `Next::write()`.
    fn on_response(&mut self, response: &mut Response) -> Next {
		*response.headers_mut() = self.response_headers();
		if self.response.is_none() {
			response.set_status(hyper::status::StatusCode::MethodNotAllowed);
		}
		Next::write()
	}

    /// This event occurs each time the `Response` is ready to be written to.
    fn on_response_writable(&mut self, encoder: &mut Encoder<HttpStream>) -> Next {
		if let Some(ref response) = self.response {
			let bytes = response.as_bytes();
			if bytes.len() == self.write_pos {
				Next::end()
			} else {
				match encoder.write(&bytes[self.write_pos ..]) {
					Ok(0) => {
						Next::write()
					}
					Ok(bytes) => {
						self.write_pos += bytes;
						Next::write()
					}
					Err(e) => match e.kind() {
						::std::io::ErrorKind::WouldBlock => Next::write(),
						_ => {
							//trace!("Write error: {}", e);
							Next::end()
						}
					}
				}
			}
		} else {
			Next::end()
		}
	}
}

/// jsonrpc http server.
///
/// ```no_run
/// extern crate jsonrpc_core;
/// extern crate jsonrpc_http_server;
///
/// use std::sync::Arc;
/// use jsonrpc_core::*;
/// use jsonrpc_http_server::*;
///
/// struct SayHello;
/// impl MethodCommand for SayHello {
/// 	fn execute(&self, _params: Params) -> Result<Value, Error> {
/// 		Ok(Value::String("hello".to_string()))
/// 	}
/// }
///
/// fn main() {
/// 	let io = IoHandler::new();
/// 	io.add_method("say_hello", SayHello);
/// 	let _server = Server::start(&"127.0.0.1:3030".parse().unwrap(), Arc::new(io), AccessControlAllowOrigin::Null);
/// }
/// ```
pub struct Server {
	server: Option<hyper::server::Listening>,
}

impl Server {
	pub fn start(addr: &SocketAddr, jsonrpc_handler: Arc<IoHandler>, cors_domain: AccessControlAllowOrigin) -> ServerResult {
		let srv = try!(try!(hyper::Server::http(addr)).handle(move |_| ServerHandler::new(jsonrpc_handler.clone(), cors_domain.clone())));
		Ok(Server {
			server: Some(srv),
		})
	}
}

impl Drop for Server {
	fn drop(&mut self) {
		self.server.take().unwrap().close()
	}
}
<|endoftext|>


<commit_before>use std::io;
use std::io::prelude::*;
use std::io::{BufReader};
use std::fs::File;
use std::process::{ChildStdout, Command, Stdio, ExitStatus};
use std::path::{PathBuf};
use std::thread;
use std::sync::Mutex;
use std::ops::DerefMut;

use std::os::unix::io::FromRawFd;
use std::os::unix::io::AsRawFd;

pub enum Output {
    Parent,
    Ignore,
    FailOnOutput,
    ToFile(PathBuf),
}

pub fn output_to_file(path: &str) -> Output {
    Output::ToFile(PathBuf::from(path))
}

pub fn output() -> DealWithOutput {
    DealWithOutput { stdout: None, stderr: Output::Parent }
}

impl DealWithOutput {
    pub fn stderr(&mut self, stderr: Output) -> &mut Self {
        self.stderr = stderr;
        self
    }

    pub fn stdout(&mut self, stdout: Output) -> &mut Self {
        self.stdout = Some(stdout);
        self
    }
}

pub struct DealWithOutput { stderr: Output, stdout: Option<Output> }

// Feed the input as stdin to the process and wait for the process to finish
pub fn process_as_consumer<R: Read>(
    deal_with: &mut DealWithOutput,
    mut input: R,
    cmd_args: (String, Vec<String>))
    -> io::Result<ExitStatus>
{
    let mut cmd = build_command(cmd_args);

    cmd.stdin(Stdio::piped());
    setup_stderr(&deal_with.stderr, &mut cmd)?;
    match deal_with.stdout {
        None => {}
        Some(ref stdout) => {
            setup_stdout(&stdout, &mut cmd)?;
        }
    }

    let mut process = cmd.spawn()?;
    let mut stdin = process.stdin.take().expect("impossible! no stdin");

    output_optional_handle(&deal_with.stderr, &mut process.stderr)?;
    match deal_with.stdout {
        None => {}
        Some(ref stdout) => {
            output_optional_handle(&stdout, &mut process.stdout)?;
        }
    }

    io::copy(&mut input, &mut stdin)?;
    let status = process.wait()?;
    Ok(status)
}

// Provide an iterator interface to a process
//
// Start a process for the given exe and args.
// Return a buffer or the error encountered when starting the process
//
// Feed input (if given) to its stdin (in a separate thread)
// Return a reader of the stdout
//
// Check stder, and wiat for the exit code on separate threads
//
// If any of the threads have failures, including if the proces has a non-zero exit code,
// panic in the that separate thread.
// TODO: the caller should be signalled about the error
pub fn process_as_iterator<R>(deal_with: &mut DealWithOutput, input_opt: Option<R>, cmd_args: (String, Vec<String>)) -> io::Result<BufReader<ChildStdout>>
    where R: Read + Send + 'static
{
    let mut cmd = build_command(cmd_args);

    // setup stdout
    cmd.stdout(Stdio::piped());
    if let Some(_) = input_opt {
        cmd.stdin(Stdio::piped());
    }

    setup_stderr(&deal_with.stderr, &mut cmd)?;

    let mut process = cmd.spawn()?;
    let stdout = process.stdout.take().expect("impossible! no stdout");

    output_optional_handle(&deal_with.stderr, &mut process.stderr)?;

    // feed input to stdin
    if let Some(input) = input_opt {
        let mut stdin = process.stdin.take().expect("impossible! no stdin");
        let input_mutex = Mutex::new(input);
        thread::spawn(move || {
            let mut inp = input_mutex.lock().expect("locking stdin input");
            io::copy(inp.deref_mut(), &mut stdin)
              .expect("error writing stdin");
        });
    }

    // wait for the process to exit successfully
    thread::spawn(move || {
        // assert that the process exits successfully
        let result = process.wait()
              .expect("error writing for the process to stop");
        if !result.success() {
            panic!("non-zero exit code {:?}", result.code());
        }
    });

    Ok(BufReader::new(stdout))
}

fn setup_stderr(deal_with_stderr: &Output, cmd: &mut Command) -> io::Result<()> {
    // setup stderr
    match deal_with_stderr {
      &Output::Parent => {}
      &Output::Ignore => {
          cmd.stderr(Stdio::null());
      }
      &Output::FailOnOutput => {
          cmd.stderr(Stdio::piped());
      }
      &Output::ToFile(ref path) => {
          if cfg!(windows) {
              cmd.stderr(Stdio::piped());
          } else {
              let file = File::create(path)?;
              unsafe {
                cmd.stderr(Stdio::from_raw_fd(file.as_raw_fd()));
              }
          }
      }
    }
    Ok(())
}

fn setup_stdout(deal_with_stdout: &Output, cmd: &mut Command) -> io::Result<()> {
    // setup stderr
    match deal_with_stdout {
      &Output::Parent => {}
      &Output::Ignore => {
          cmd.stdout(Stdio::null());
      }
      &Output::FailOnOutput => {
          cmd.stdout(Stdio::piped());
      }
      &Output::ToFile(ref path) => {
          if cfg!(windows) {
              cmd.stdout(Stdio::piped());
          } else {
              let file = File::create(path)?;
              unsafe {
                cmd.stdout(Stdio::from_raw_fd(file.as_raw_fd()));
              }
          }
      }
    }
    Ok(())
}

// Build up the command from the arguments
fn build_command(cmd_args: (String, Vec<String>)) -> Command {
    // Build up the command from the arguments
    let (exe, args) = cmd_args;
    let mut cmd = Command::new(exe);
    for arg in args { cmd.arg(arg); }
    return cmd
}

fn output_optional_handle<R: Read + Send + 'static>(deal_with_output: &Output, opt_handle: &mut Option<R>) -> io::Result<()> {
    if let &Output::FailOnOutput = deal_with_output {
        let handle = opt_handle.take().expect("impossible! no output handle");
        let _ = thread::spawn(move || {
            let mut output = Vec::new();
            let size = handle.take(1).read_to_end(&mut output).expect("error reading output");
            if size > 0 {
              panic!("got unexpected output");
            }
        });
    } else {
        if let &Output::ToFile(ref path) = deal_with_output {
            if cfg!(windows) {
                let mut handle = opt_handle.take().expect("impossible! no output handle");
                let mut file = File::create(path)?;
                let _ = thread::spawn(move || {
                    io::copy(&mut handle, &mut file)
                      .expect("error writing output to a file");
                });
            }
        }
    }

    Ok(())
}
<commit_msg>add a separate ToFd option<commit_after>use std::io;
use std::io::prelude::*;
use std::io::{BufReader};
use std::fs::File;
use std::process::{ChildStdout, Command, Stdio, ExitStatus};
use std::path::{PathBuf};
use std::thread;
use std::sync::Mutex;
use std::ops::DerefMut;

use std::os::unix::io::FromRawFd;
use std::os::unix::io::AsRawFd;

pub enum Output {
    Parent,
    Ignore,
    FailOnOutput,
    ToFd(File),
    // only works on Unix
    ToPath(PathBuf),
}

pub fn output_to_path(path: &str) -> Output {
    Output::ToPath(PathBuf::from(path))
}

pub fn output() -> DealWithOutput {
    DealWithOutput { stdout: None, stderr: Output::Parent }
}

impl DealWithOutput {
    pub fn stderr(&mut self, stderr: Output) -> &mut Self {
        self.stderr = stderr;
        self
    }

    pub fn stdout(&mut self, stdout: Output) -> &mut Self {
        self.stdout = Some(stdout);
        self
    }
}

pub struct DealWithOutput { stderr: Output, stdout: Option<Output> }

// Feed the input as stdin to the process and wait for the process to finish
pub fn process_as_consumer<R: Read>(
    deal_with: &mut DealWithOutput,
    mut input: R,
    cmd_args: (String, Vec<String>))
    -> io::Result<ExitStatus>
{
    let mut cmd = build_command(cmd_args);

    cmd.stdin(Stdio::piped());
    setup_stderr(&deal_with.stderr, &mut cmd)?;
    match deal_with.stdout {
        None => {}
        Some(ref stdout) => {
            setup_stdout(&stdout, &mut cmd)?;
        }
    }

    let mut process = cmd.spawn()?;
    let mut stdin = process.stdin.take().expect("impossible! no stdin");

    output_optional_handle(&deal_with.stderr, &mut process.stderr)?;
    match deal_with.stdout {
        None => {}
        Some(ref stdout) => {
            output_optional_handle(&stdout, &mut process.stdout)?;
        }
    }

    io::copy(&mut input, &mut stdin)?;
    let status = process.wait()?;
    Ok(status)
}

// Provide an iterator interface to a process
//
// Start a process for the given exe and args.
// Return a buffer or the error encountered when starting the process
//
// Feed input (if given) to its stdin (in a separate thread)
// Return a reader of the stdout
//
// Check stder, and wiat for the exit code on separate threads
//
// If any of the threads have failures, including if the proces has a non-zero exit code,
// panic in the that separate thread.
// TODO: the caller should be signalled about the error
pub fn process_as_iterator<R>(deal_with: &mut DealWithOutput, input_opt: Option<R>, cmd_args: (String, Vec<String>)) -> io::Result<BufReader<ChildStdout>>
    where R: Read + Send + 'static
{
    let mut cmd = build_command(cmd_args);

    // setup stdout
    cmd.stdout(Stdio::piped());
    if let Some(_) = input_opt {
        cmd.stdin(Stdio::piped());
    }

    setup_stderr(&deal_with.stderr, &mut cmd)?;

    let mut process = cmd.spawn()?;
    let stdout = process.stdout.take().expect("impossible! no stdout");

    output_optional_handle(&deal_with.stderr, &mut process.stderr)?;

    // feed input to stdin
    if let Some(input) = input_opt {
        let mut stdin = process.stdin.take().expect("impossible! no stdin");
        let input_mutex = Mutex::new(input);
        thread::spawn(move || {
            let mut inp = input_mutex.lock().expect("locking stdin input");
            io::copy(inp.deref_mut(), &mut stdin)
              .expect("error writing stdin");
        });
    }

    // wait for the process to exit successfully
    thread::spawn(move || {
        // assert that the process exits successfully
        let result = process.wait()
              .expect("error writing for the process to stop");
        if !result.success() {
            panic!("non-zero exit code {:?}", result.code());
        }
    });

    Ok(BufReader::new(stdout))
}

fn setup_stderr(deal_with_stderr: &Output, cmd: &mut Command) -> io::Result<()> {
    // setup stderr
    match deal_with_stderr {
      &Output::Parent => {}
      &Output::Ignore => {
          cmd.stderr(Stdio::null());
      }
      &Output::FailOnOutput => {
          cmd.stderr(Stdio::piped());
      }
      &Output::ToFd(ref file) => {
          unsafe {
            cmd.stderr(Stdio::from_raw_fd(file.as_raw_fd()));
          }
      }
      &Output::ToPath(_) => {
          cmd.stderr(Stdio::piped());
      }
    }
    Ok(())
}

fn setup_stdout(deal_with_stdout: &Output, cmd: &mut Command) -> io::Result<()> {
    // setup stderr
    match deal_with_stdout {
      &Output::Parent => {}
      &Output::Ignore => {
          cmd.stdout(Stdio::null());
      }
      &Output::FailOnOutput => {
          cmd.stdout(Stdio::piped());
      }
      &Output::ToFd(ref file) => {
          unsafe {
            cmd.stdout(Stdio::from_raw_fd(file.as_raw_fd()));
          }
      }
      &Output::ToPath(_) => {
          cmd.stdout(Stdio::piped());
      }
    }
    Ok(())
}

// Build up the command from the arguments
fn build_command(cmd_args: (String, Vec<String>)) -> Command {
    // Build up the command from the arguments
    let (exe, args) = cmd_args;
    let mut cmd = Command::new(exe);
    for arg in args { cmd.arg(arg); }
    return cmd
}

fn output_optional_handle<R: Read + Send + 'static>(deal_with_output: &Output, opt_handle: &mut Option<R>) -> io::Result<()> {
    if let &Output::FailOnOutput = deal_with_output {
        let handle = opt_handle.take().expect("impossible! no output handle");
        let _ = thread::spawn(move || {
            let mut output = Vec::new();
            let size = handle.take(1).read_to_end(&mut output).expect("error reading output");
            if size > 0 {
              panic!("got unexpected output");
            }
        });
    } else {
        if let &Output::ToPath(ref path) = deal_with_output {
            let mut handle = opt_handle.take().expect("impossible! no output handle");
            let mut file = File::create(path)?;
            let _ = thread::spawn(move || {
                io::copy(&mut handle, &mut file)
                  .expect("error writing output to a file");
            });
        }
    }

    Ok(())
}
<|endoftext|>


<commit_before>/// Spark id of the user
pub type PersonId = String;

/// Describes a state of the bot
#[derive(Debug)]
pub struct Bot {
    pub persons: Vec<PersonId>,
}

impl Bot {
    pub fn new() -> Bot {
        return Bot { persons: Vec::new() };
    }
}

#[derive(Debug)]
pub enum Action {
    Enable(PersonId),
    Disable(PersonId),
    Help,
    Unknown,
}

/// Action controller
pub fn update(action: Action, bot: Bot) -> Bot {
    bot
}
<commit_msg>Implement actions.<commit_after>use std::collections::HashSet;

/// Spark id of the user
pub type PersonId = String;

/// Describes a state of the bot
#[derive(Debug)]
pub struct Bot {
    pub persons: HashSet<PersonId>,
}

impl Bot {
    pub fn new() -> Bot {
        return Bot { persons: HashSet::new() };
    }
}

#[derive(Debug)]
pub enum Action {
    Enable(PersonId),
    Disable(PersonId),
    Help,
    Unknown,
}

/// Action controller
pub fn update(action: Action, bot: Bot) -> Bot {
    let mut bot = bot;
    match action {
        Action::Enable(person_id) => {
            bot.persons.insert(person_id);
        }
        Action::Disable(person_id) => {
            bot.persons.remove(&person_id);
        }
        _ => (),
    }
    bot
}
<|endoftext|>