<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 base_db::CrateId;
use hir_expand::name::Name;
use hir_expand::MacroDefKind;
use once_cell::sync::Lazy;
use rustc_hash::{FxHashMap, FxHashSet};
use test_utils::mark;

use crate::ModuleId;
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>,
    /// Traits imported via `use Trait as _;`.
    unnamed_trait_imports: FxHashMap<TraitId, Visibility>,
    /// 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 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,
            })
            .chain(self.unnamed_trait_imports.keys().copied())
    }

    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 unnamed_trait_vis(&self, tr: TraitId) -> Option<Visibility> {
        self.unnamed_trait_imports.get(&tr).copied()
    }

    pub(crate) fn push_unnamed_trait(&mut self, tr: TraitId, vis: Visibility) {
        self.unnamed_trait_imports.insert(tr, vis);
    }

    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 = (Option<Name>, PerNs)> + 'a {
        self.entries().map(|(name, res)| (Some(name.clone()), res)).chain(
            self.unnamed_trait_imports
                .iter()
                .map(|(tr, vis)| (None, PerNs::types(ModuleDefId::TraitId(*tr), *vis))),
        )
    }

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

    /// Marks everything that is not a procedural macro as private to `this_module`.
    pub(crate) fn censor_non_proc_macros(&mut self, this_module: ModuleId) {
        for vis in self
            .types
            .values_mut()
            .chain(self.values.values_mut())
            .map(|(_, v)| v)
            .chain(self.unnamed_trait_imports.values_mut())
        {
            *vis = Visibility::Module(this_module);
        }

        for (mac, vis) in self.macros.values_mut() {
            if let MacroDefKind::ProcMacro(_) = mac.kind {
                // FIXME: Technically this is insufficient since reexports of proc macros are also
                // forbidden. Practically nobody does that.
                continue;
            }

            *vis = Visibility::Module(this_module);
        }
    }
}

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 iterator chain<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 base_db::CrateId;
use hir_expand::name::Name;
use hir_expand::MacroDefKind;
use once_cell::sync::Lazy;
use rustc_hash::{FxHashMap, FxHashSet};
use test_utils::mark;

use crate::ModuleId;
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>,
    /// Traits imported via `use Trait as _;`.
    unnamed_trait_imports: FxHashMap<TraitId, Visibility>,
    /// 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 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,
            })
            .chain(self.unnamed_trait_imports.keys().copied())
    }

    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 unnamed_trait_vis(&self, tr: TraitId) -> Option<Visibility> {
        self.unnamed_trait_imports.get(&tr).copied()
    }

    pub(crate) fn push_unnamed_trait(&mut self, tr: TraitId, vis: Visibility) {
        self.unnamed_trait_imports.insert(tr, vis);
    }

    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 = (Option<Name>, PerNs)> + 'a {
        self.entries().map(|(name, res)| (Some(name.clone()), res)).chain(
            self.unnamed_trait_imports
                .iter()
                .map(|(tr, vis)| (None, PerNs::types(ModuleDefId::TraitId(*tr), *vis))),
        )
    }

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

    /// Marks everything that is not a procedural macro as private to `this_module`.
    pub(crate) fn censor_non_proc_macros(&mut self, this_module: ModuleId) {
        self.types
            .values_mut()
            .chain(self.values.values_mut())
            .map(|(_, v)| v)
            .chain(self.unnamed_trait_imports.values_mut())
            .for_each(|vis| *vis = Visibility::Module(this_module));

        for (mac, vis) in self.macros.values_mut() {
            if let MacroDefKind::ProcMacro(_) = mac.kind {
                // FIXME: Technically this is insufficient since reexports of proc macros are also
                // forbidden. Practically nobody does that.
                continue;
            }

            *vis = Visibility::Module(this_module);
        }
    }
}

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 futures::{sync::mpsc::Sender, Future, Sink};
use godcoin::prelude::*;
use parking_lot::RwLock;
use std::{collections::HashMap, net::SocketAddr, sync::Arc};
use tokio_tungstenite::tungstenite::Message;

#[derive(Clone)]
pub struct SubscriptionPool {
    clients: Arc<RwLock<HashMap<SocketAddr, Sender<Message>>>>,
}

impl SubscriptionPool {
    #[inline]
    pub fn new() -> Self {
        Self {
            clients: Arc::new(RwLock::new(HashMap::with_capacity(1024))),
        }
    }

    #[inline]
    pub fn insert(&self, addr: SocketAddr, tx: Sender<Message>) {
        self.clients.write().insert(addr, tx);
    }

    #[inline]
    pub fn remove(&self, addr: SocketAddr) {
        self.clients.write().remove(&addr);
    }

    pub fn broadcast(&self, msg: rpc::Response) {
        let msg = {
            let mut buf = Vec::with_capacity(65536);
            let res = Msg {
                id: u32::max_value(),
                body: Body::Response(msg.clone()),
            };
            res.serialize(&mut buf);
            Message::Binary(buf)
        };

        let clients = self.clients.read();
        for client in clients.values() {
            // Errors only occur when the other end is dropped, it is the pool managers responsibility to remove any
            // disconnected clients
            tokio::spawn(
                client
                    .clone()
                    .send(msg.clone())
                    .map(|_sink| ())
                    .map_err(|_| ()),
            );
        }
    }
}

impl Default for SubscriptionPool {
    #[inline]
    fn default() -> Self {
        SubscriptionPool::new()
    }
}
<commit_msg>Remove redundant clone<commit_after>use futures::{sync::mpsc::Sender, Future, Sink};
use godcoin::prelude::*;
use parking_lot::RwLock;
use std::{collections::HashMap, net::SocketAddr, sync::Arc};
use tokio_tungstenite::tungstenite::Message;

#[derive(Clone)]
pub struct SubscriptionPool {
    clients: Arc<RwLock<HashMap<SocketAddr, Sender<Message>>>>,
}

impl SubscriptionPool {
    #[inline]
    pub fn new() -> Self {
        Self {
            clients: Arc::new(RwLock::new(HashMap::with_capacity(1024))),
        }
    }

    #[inline]
    pub fn insert(&self, addr: SocketAddr, tx: Sender<Message>) {
        self.clients.write().insert(addr, tx);
    }

    #[inline]
    pub fn remove(&self, addr: SocketAddr) {
        self.clients.write().remove(&addr);
    }

    pub fn broadcast(&self, msg: rpc::Response) {
        let msg = {
            let mut buf = Vec::with_capacity(65536);
            let res = Msg {
                id: u32::max_value(),
                body: Body::Response(msg),
            };
            res.serialize(&mut buf);
            Message::Binary(buf)
        };

        let clients = self.clients.read();
        for client in clients.values() {
            // Errors only occur when the other end is dropped, it is the pool managers responsibility to remove any
            // disconnected clients
            tokio::spawn(
                client
                    .clone()
                    .send(msg.clone())
                    .map(|_sink| ())
                    .map_err(|_| ()),
            );
        }
    }
}

impl Default for SubscriptionPool {
    #[inline]
    fn default() -> Self {
        SubscriptionPool::new()
    }
}
<|endoftext|>


<commit_before>//! Lock-free intrusive linked list.
//!
//! Ideas from Michael.  High Performance Dynamic Lock-Free Hash Tables and List-Based Sets.  SPAA
//! 2002.  http://dl.acm.org/citation.cfm?id=564870.564881

use core::marker::PhantomData;
use core::sync::atomic::Ordering::{Acquire, Relaxed, Release};

use {unprotected, Atomic, Guard, Shared};

/// An entry in a linked list.
///
/// An Entry is accessed from multiple threads, so it would be beneficial to put it in a different
/// cache-line than thread-local data in terms of performance.
#[derive(Debug)]
pub struct Entry {
    /// The next entry in the linked list.
    /// If the tag is 1, this entry is marked as deleted.
    next: Atomic<Entry>,
}

/// Implementing this trait asserts that the type `T` can be used as an element in the intrusive
/// linked list defined in this module. `T` has to contain (or otherwise be linked to) an instance
/// of `Entry`.
///
/// # Example
///
/// ```ignore
/// struct A {
///     entry: Entry,
///     data: usize,
/// }
///
/// impl IsElement<A> for A {
///     fn entry_of(a: &A) -> &Entry {
///         let entry_ptr = ((a as usize) + offset_of!(A, entry)) as *const Entry;
///         unsafe { &*entry_ptr }
///     }
///
///     unsafe fn element_of(entry: &Entry) -> &T {
///         let elem_ptr = ((entry as usize) - offset_of!(A, entry)) as *const T;
///         &*elem_ptr
///     }
///
///     unsafe fn finalize(entry: &Entry, guard: &Guard) {
///         guard.defer_destroy(Shared::from(Self::element_of(entry) as *const _));
///     }
/// }
/// ```
///
/// This trait is implemented on a type separate from `T` (although it can be just `T`), because
/// one type might be placeable into multiple lists, in which case it would require multiple
/// implementations of `IsElement`. In such cases, each struct implementing `IsElement<T>`
/// represents a distinct `Entry` in `T`.
///
/// For example, we can insert the following struct into two lists using `entry1` for one
/// and `entry2` for the other:
///
/// ```ignore
/// struct B {
///     entry1: Entry,
///     entry2: Entry,
///     data: usize,
/// }
/// ```
///
pub trait IsElement<T> {
    /// Returns a reference to this element's `Entry`.
    fn entry_of(&T) -> &Entry;

    /// Given a reference to an element's entry, returns that element.
    ///
    /// ```ignore
    /// let elem = ListElement::new();
    /// assert_eq!(elem.entry_of(),
    ///            unsafe { ListElement::element_of(elem.entry_of()) } );
    /// ```
    ///
    /// # Safety
    ///
    /// The caller has to guarantee that the `Entry` is called with was retrieved from an instance
    /// of the element type (`T`).
    unsafe fn element_of(&Entry) -> &T;

    /// The function that is called when an entry is unlinked from list.
    ///
    /// # Safety
    ///
    /// The caller has to guarantee that the `Entry` is called with was retrieved from an instance
    /// of the element type (`T`).
    unsafe fn finalize(&Entry, &Guard);
}

/// A lock-free, intrusive linked list of type `T`.
#[derive(Debug)]
pub struct List<T, C: IsElement<T> = T> {
    /// The head of the linked list.
    head: Atomic<Entry>,

    /// The phantom data for using `T` and `C`.
    _marker: PhantomData<(T, C)>,
}

/// An iterator used for retrieving values from the list.
pub struct Iter<'g, T: 'g, C: IsElement<T>> {
    /// The guard that protects the iteration.
    guard: &'g Guard,

    /// Pointer from the predecessor to the current entry.
    pred: &'g Atomic<Entry>,

    /// The current entry.
    curr: Shared<'g, Entry>,

    /// The list head, needed for restarting iteration.
    head: &'g Atomic<Entry>,

    /// Logically, we store a borrow of an instance of `T` and
    /// use the type information from `C`.
    _marker: PhantomData<(&'g T, C)>,
}

/// An error that occurs during iteration over the list.
#[derive(PartialEq, Debug)]
pub enum IterError {
    /// A concurrent thread modified the state of the list at the same place that this iterator
    /// was inspecting. Subsequent iteration will restart from the beginning of the list.
    Stalled,
}

impl Default for Entry {
    /// Returns the empty entry.
    fn default() -> Self {
        Self {
            next: Atomic::null(),
        }
    }
}

impl Entry {
    /// Marks this entry as deleted, deferring the actual deallocation to a later iteration.
    ///
    /// # Safety
    ///
    /// The entry should be a member of a linked list, and it should not have been deleted.
    /// It should be safe to call `C::finalize` on the entry after the `guard` is dropped, where `C`
    /// is the associated helper for the linked list.
    pub unsafe fn delete(&self, guard: &Guard) {
        self.next.fetch_or(1, Release, guard);
    }
}

impl<T, C: IsElement<T>> List<T, C> {
    /// Returns a new, empty linked list.
    pub fn new() -> Self {
        Self {
            head: Atomic::null(),
            _marker: PhantomData,
        }
    }

    /// Inserts `entry` into the head of the list.
    ///
    /// # Safety
    ///
    /// You should guarantee that:
    ///
    /// - `container` is not null
    /// - `container` is immovable, e.g. inside an `Owned`
    /// - the same `Entry` is not inserted more than once
    /// - the inserted object will be removed before the list is dropped
    pub unsafe fn insert<'g>(&'g self, container: Shared<'g, T>, guard: &'g Guard) {
        // Insert right after head, i.e. at the beginning of the list.
        let to = &self.head;
        // Get the intrusively stored Entry of the new element to insert.
        let entry: &Entry = C::entry_of(container.deref());
        // Make a Shared ptr to that Entry.
        let entry_ptr = Shared::from(entry as *const _);
        // Read the current successor of where we want to insert.
        let mut next = to.load(Relaxed, guard);

        loop {
            // Set the Entry of the to-be-inserted element to point to the previous successor of
            // `to`.
            entry.next.store(next, Relaxed);
            match to.compare_and_set_weak(next, entry_ptr, Release, guard) {
                Ok(_) => break,
                // We lost the race or weak CAS failed spuriously. Update the successor and try
                // again.
                Err(err) => next = err.current,
            }
        }
    }

    /// Returns an iterator over all objects.
    ///
    /// # Caveat
    ///
    /// Every object that is inserted at the moment this function is called and persists at least
    /// until the end of iteration will be returned. Since this iterator traverses a lock-free
    /// linked list that may be concurrently modified, some additional caveats apply:
    ///
    /// 1. If a new object is inserted during iteration, it may or may not be returned.
    /// 2. If an object is deleted during iteration, it may or may not be returned.
    /// 3. The iteration may be aborted when it lost in a race condition. In this case, the winning
    ///    thread will continue to iterate over the same list.
    pub fn iter<'g>(&'g self, guard: &'g Guard) -> Iter<'g, T, C> {
        Iter {
            guard,
            pred: &self.head,
            curr: self.head.load(Acquire, guard),
            head: &self.head,
            _marker: PhantomData,
        }
    }
}

impl<T, C: IsElement<T>> Drop for List<T, C> {
    fn drop(&mut self) {
        unsafe {
            let guard = &unprotected();
            let mut curr = self.head.load(Relaxed, guard);
            while let Some(c) = curr.as_ref() {
                let succ = c.next.load(Relaxed, guard);
                // Verify that all elements have been removed from the list.
                assert_eq!(succ.tag(), 1);

                C::finalize(curr.deref(), guard);
                curr = succ;
            }
        }
    }
}

impl<'g, T: 'g, C: IsElement<T>> Iterator for Iter<'g, T, C> {
    type Item = Result<&'g T, IterError>;

    fn next(&mut self) -> Option<Self::Item> {
        while let Some(c) = unsafe { self.curr.as_ref() } {
            let succ = c.next.load(Acquire, self.guard);

            if succ.tag() == 1 {
                // This entry was removed. Try unlinking it from the list.
                let succ = succ.with_tag(0);

                // The tag should never be zero, because removing a node after a logically deleted
                // node leaves the list in an invalid state.
                debug_assert!(self.curr.tag() == 0);

                match self
                    .pred
                    .compare_and_set(self.curr, succ, Acquire, self.guard)
                {
                    Ok(_) => {
                        // We succeeded in unlinking this element from the list, so we have to
                        // schedule deallocation. Deferred drop is okay, because `list.delete()`
                        // can only be called if `T: 'static`.
                        unsafe {
                            C::finalize(self.curr.deref(), self.guard);
                        }

                        // Move over the removed by only advancing `curr`, not `pred`.
                        self.curr = succ;
                        continue;
                    }
                    Err(_) => {
                        // A concurrent thread modified the predecessor node. Since it might've
                        // been deleted, we need to restart from `head`.
                        self.pred = self.head;
                        self.curr = self.head.load(Acquire, self.guard);

                        return Some(Err(IterError::Stalled));
                    }
                }
            }

            // Move one step forward.
            self.pred = &c.next;
            self.curr = succ;

            return Some(Ok(unsafe { C::element_of(c) }));
        }

        // We reached the end of the list.
        None
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crossbeam_utils::thread;
    use std::sync::Barrier;
    use {Collector, Owned};

    impl IsElement<Entry> for Entry {
        fn entry_of(entry: &Entry) -> &Entry {
            entry
        }

        unsafe fn element_of(entry: &Entry) -> &Entry {
            entry
        }

        unsafe fn finalize(entry: &Entry, guard: &Guard) {
            guard.defer_destroy(Shared::from(Self::element_of(entry) as *const _));
        }
    }

    /// Checks whether the list retains inserted elements
    /// and returns them in the correct order.
    #[test]
    fn insert() {
        let collector = Collector::new();
        let handle = collector.register();
        let guard = handle.pin();

        let l: List<Entry> = List::new();

        let e1 = Owned::new(Entry::default()).into_shared(&guard);
        let e2 = Owned::new(Entry::default()).into_shared(&guard);
        let e3 = Owned::new(Entry::default()).into_shared(&guard);

        unsafe {
            l.insert(e1, &guard);
            l.insert(e2, &guard);
            l.insert(e3, &guard);
        }

        let mut iter = l.iter(&guard);
        let maybe_e3 = iter.next();
        assert!(maybe_e3.is_some());
        assert!(maybe_e3.unwrap().unwrap() as *const Entry == e3.as_raw());
        let maybe_e2 = iter.next();
        assert!(maybe_e2.is_some());
        assert!(maybe_e2.unwrap().unwrap() as *const Entry == e2.as_raw());
        let maybe_e1 = iter.next();
        assert!(maybe_e1.is_some());
        assert!(maybe_e1.unwrap().unwrap() as *const Entry == e1.as_raw());
        assert!(iter.next().is_none());

        unsafe {
            e1.as_ref().unwrap().delete(&guard);
            e2.as_ref().unwrap().delete(&guard);
            e3.as_ref().unwrap().delete(&guard);
        }
    }

    /// Checks whether elements can be removed from the list and whether
    /// the correct elements are removed.
    #[test]
    fn delete() {
        let collector = Collector::new();
        let handle = collector.register();
        let guard = handle.pin();

        let l: List<Entry> = List::new();

        let e1 = Owned::new(Entry::default()).into_shared(&guard);
        let e2 = Owned::new(Entry::default()).into_shared(&guard);
        let e3 = Owned::new(Entry::default()).into_shared(&guard);
        unsafe {
            l.insert(e1, &guard);
            l.insert(e2, &guard);
            l.insert(e3, &guard);
            e2.as_ref().unwrap().delete(&guard);
        }

        let mut iter = l.iter(&guard);
        let maybe_e3 = iter.next();
        assert!(maybe_e3.is_some());
        assert!(maybe_e3.unwrap().unwrap() as *const Entry == e3.as_raw());
        let maybe_e1 = iter.next();
        assert!(maybe_e1.is_some());
        assert!(maybe_e1.unwrap().unwrap() as *const Entry == e1.as_raw());
        assert!(iter.next().is_none());

        unsafe {
            e1.as_ref().unwrap().delete(&guard);
            e3.as_ref().unwrap().delete(&guard);
        }

        let mut iter = l.iter(&guard);
        assert!(iter.next().is_none());
    }

    const THREADS: usize = 8;
    const ITERS: usize = 512;

    /// Contends the list on insert and delete operations to make sure they can run concurrently.
    #[test]
    fn insert_delete_multi() {
        let collector = Collector::new();

        let l: List<Entry> = List::new();
        let b = Barrier::new(THREADS);

        thread::scope(|s| {
            for _ in 0..THREADS {
                s.spawn(|_| {
                    b.wait();

                    let handle = collector.register();
                    let guard: Guard = handle.pin();
                    let mut v = Vec::with_capacity(ITERS);

                    for _ in 0..ITERS {
                        let e = Owned::new(Entry::default()).into_shared(&guard);
                        v.push(e);
                        unsafe {
                            l.insert(e, &guard);
                        }
                    }

                    for e in v {
                        unsafe {
                            e.as_ref().unwrap().delete(&guard);
                        }
                    }
                });
            }
        })
        .unwrap();

        let handle = collector.register();
        let guard = handle.pin();

        let mut iter = l.iter(&guard);
        assert!(iter.next().is_none());
    }

    /// Contends the list on iteration to make sure that it can be iterated over concurrently.
    #[test]
    fn iter_multi() {
        let collector = Collector::new();

        let l: List<Entry> = List::new();
        let b = Barrier::new(THREADS);

        thread::scope(|s| {
            for _ in 0..THREADS {
                s.spawn(|_| {
                    b.wait();

                    let handle = collector.register();
                    let guard: Guard = handle.pin();
                    let mut v = Vec::with_capacity(ITERS);

                    for _ in 0..ITERS {
                        let e = Owned::new(Entry::default()).into_shared(&guard);
                        v.push(e);
                        unsafe {
                            l.insert(e, &guard);
                        }
                    }

                    let mut iter = l.iter(&guard);
                    for _ in 0..ITERS {
                        assert!(iter.next().is_some());
                    }

                    for e in v {
                        unsafe {
                            e.as_ref().unwrap().delete(&guard);
                        }
                    }
                });
            }
        })
        .unwrap();

        let handle = collector.register();
        let guard = handle.pin();

        let mut iter = l.iter(&guard);
        assert!(iter.next().is_none());
    }
}
<commit_msg>Reduce stall in list iteration<commit_after>//! Lock-free intrusive linked list.
//!
//! Ideas from Michael.  High Performance Dynamic Lock-Free Hash Tables and List-Based Sets.  SPAA
//! 2002.  http://dl.acm.org/citation.cfm?id=564870.564881

use core::marker::PhantomData;
use core::sync::atomic::Ordering::{Acquire, Relaxed, Release};

use {unprotected, Atomic, Guard, Shared};

/// An entry in a linked list.
///
/// An Entry is accessed from multiple threads, so it would be beneficial to put it in a different
/// cache-line than thread-local data in terms of performance.
#[derive(Debug)]
pub struct Entry {
    /// The next entry in the linked list.
    /// If the tag is 1, this entry is marked as deleted.
    next: Atomic<Entry>,
}

/// Implementing this trait asserts that the type `T` can be used as an element in the intrusive
/// linked list defined in this module. `T` has to contain (or otherwise be linked to) an instance
/// of `Entry`.
///
/// # Example
///
/// ```ignore
/// struct A {
///     entry: Entry,
///     data: usize,
/// }
///
/// impl IsElement<A> for A {
///     fn entry_of(a: &A) -> &Entry {
///         let entry_ptr = ((a as usize) + offset_of!(A, entry)) as *const Entry;
///         unsafe { &*entry_ptr }
///     }
///
///     unsafe fn element_of(entry: &Entry) -> &T {
///         let elem_ptr = ((entry as usize) - offset_of!(A, entry)) as *const T;
///         &*elem_ptr
///     }
///
///     unsafe fn finalize(entry: &Entry, guard: &Guard) {
///         guard.defer_destroy(Shared::from(Self::element_of(entry) as *const _));
///     }
/// }
/// ```
///
/// This trait is implemented on a type separate from `T` (although it can be just `T`), because
/// one type might be placeable into multiple lists, in which case it would require multiple
/// implementations of `IsElement`. In such cases, each struct implementing `IsElement<T>`
/// represents a distinct `Entry` in `T`.
///
/// For example, we can insert the following struct into two lists using `entry1` for one
/// and `entry2` for the other:
///
/// ```ignore
/// struct B {
///     entry1: Entry,
///     entry2: Entry,
///     data: usize,
/// }
/// ```
///
pub trait IsElement<T> {
    /// Returns a reference to this element's `Entry`.
    fn entry_of(&T) -> &Entry;

    /// Given a reference to an element's entry, returns that element.
    ///
    /// ```ignore
    /// let elem = ListElement::new();
    /// assert_eq!(elem.entry_of(),
    ///            unsafe { ListElement::element_of(elem.entry_of()) } );
    /// ```
    ///
    /// # Safety
    ///
    /// The caller has to guarantee that the `Entry` is called with was retrieved from an instance
    /// of the element type (`T`).
    unsafe fn element_of(&Entry) -> &T;

    /// The function that is called when an entry is unlinked from list.
    ///
    /// # Safety
    ///
    /// The caller has to guarantee that the `Entry` is called with was retrieved from an instance
    /// of the element type (`T`).
    unsafe fn finalize(&Entry, &Guard);
}

/// A lock-free, intrusive linked list of type `T`.
#[derive(Debug)]
pub struct List<T, C: IsElement<T> = T> {
    /// The head of the linked list.
    head: Atomic<Entry>,

    /// The phantom data for using `T` and `C`.
    _marker: PhantomData<(T, C)>,
}

/// An iterator used for retrieving values from the list.
pub struct Iter<'g, T: 'g, C: IsElement<T>> {
    /// The guard that protects the iteration.
    guard: &'g Guard,

    /// Pointer from the predecessor to the current entry.
    pred: &'g Atomic<Entry>,

    /// The current entry.
    curr: Shared<'g, Entry>,

    /// The list head, needed for restarting iteration.
    head: &'g Atomic<Entry>,

    /// Logically, we store a borrow of an instance of `T` and
    /// use the type information from `C`.
    _marker: PhantomData<(&'g T, C)>,
}

/// An error that occurs during iteration over the list.
#[derive(PartialEq, Debug)]
pub enum IterError {
    /// A concurrent thread modified the state of the list at the same place that this iterator
    /// was inspecting. Subsequent iteration will restart from the beginning of the list.
    Stalled,
}

impl Default for Entry {
    /// Returns the empty entry.
    fn default() -> Self {
        Self {
            next: Atomic::null(),
        }
    }
}

impl Entry {
    /// Marks this entry as deleted, deferring the actual deallocation to a later iteration.
    ///
    /// # Safety
    ///
    /// The entry should be a member of a linked list, and it should not have been deleted.
    /// It should be safe to call `C::finalize` on the entry after the `guard` is dropped, where `C`
    /// is the associated helper for the linked list.
    pub unsafe fn delete(&self, guard: &Guard) {
        self.next.fetch_or(1, Release, guard);
    }
}

impl<T, C: IsElement<T>> List<T, C> {
    /// Returns a new, empty linked list.
    pub fn new() -> Self {
        Self {
            head: Atomic::null(),
            _marker: PhantomData,
        }
    }

    /// Inserts `entry` into the head of the list.
    ///
    /// # Safety
    ///
    /// You should guarantee that:
    ///
    /// - `container` is not null
    /// - `container` is immovable, e.g. inside an `Owned`
    /// - the same `Entry` is not inserted more than once
    /// - the inserted object will be removed before the list is dropped
    pub unsafe fn insert<'g>(&'g self, container: Shared<'g, T>, guard: &'g Guard) {
        // Insert right after head, i.e. at the beginning of the list.
        let to = &self.head;
        // Get the intrusively stored Entry of the new element to insert.
        let entry: &Entry = C::entry_of(container.deref());
        // Make a Shared ptr to that Entry.
        let entry_ptr = Shared::from(entry as *const _);
        // Read the current successor of where we want to insert.
        let mut next = to.load(Relaxed, guard);

        loop {
            // Set the Entry of the to-be-inserted element to point to the previous successor of
            // `to`.
            entry.next.store(next, Relaxed);
            match to.compare_and_set_weak(next, entry_ptr, Release, guard) {
                Ok(_) => break,
                // We lost the race or weak CAS failed spuriously. Update the successor and try
                // again.
                Err(err) => next = err.current,
            }
        }
    }

    /// Returns an iterator over all objects.
    ///
    /// # Caveat
    ///
    /// Every object that is inserted at the moment this function is called and persists at least
    /// until the end of iteration will be returned. Since this iterator traverses a lock-free
    /// linked list that may be concurrently modified, some additional caveats apply:
    ///
    /// 1. If a new object is inserted during iteration, it may or may not be returned.
    /// 2. If an object is deleted during iteration, it may or may not be returned.
    /// 3. The iteration may be aborted when it lost in a race condition. In this case, the winning
    ///    thread will continue to iterate over the same list.
    pub fn iter<'g>(&'g self, guard: &'g Guard) -> Iter<'g, T, C> {
        Iter {
            guard,
            pred: &self.head,
            curr: self.head.load(Acquire, guard),
            head: &self.head,
            _marker: PhantomData,
        }
    }
}

impl<T, C: IsElement<T>> Drop for List<T, C> {
    fn drop(&mut self) {
        unsafe {
            let guard = &unprotected();
            let mut curr = self.head.load(Relaxed, guard);
            while let Some(c) = curr.as_ref() {
                let succ = c.next.load(Relaxed, guard);
                // Verify that all elements have been removed from the list.
                assert_eq!(succ.tag(), 1);

                C::finalize(curr.deref(), guard);
                curr = succ;
            }
        }
    }
}

impl<'g, T: 'g, C: IsElement<T>> Iterator for Iter<'g, T, C> {
    type Item = Result<&'g T, IterError>;

    fn next(&mut self) -> Option<Self::Item> {
        while let Some(c) = unsafe { self.curr.as_ref() } {
            let succ = c.next.load(Acquire, self.guard);

            if succ.tag() == 1 {
                // This entry was removed. Try unlinking it from the list.
                let succ = succ.with_tag(0);

                // The tag should never be zero, because removing a node after a logically deleted
                // node leaves the list in an invalid state.
                debug_assert!(self.curr.tag() == 0);

                // Try to unlink `curr` from the list, and get the new value of `self.pred`.
                let succ = self
                    .pred
                    .compare_and_set(self.curr, succ, Acquire, self.guard)
                    .map(|_| {
                        // We succeeded in unlinking `curr`, so we have to schedule
                        // deallocation. Deferred drop is okay, because `list.delete()` can only be
                        // called if `T: 'static`.
                        unsafe {
                            C::finalize(self.curr.deref(), self.guard);
                        }

                        // `succ` is the new value of `self.pred`.
                        succ
                    })
                    .unwrap_or_else(|e| {
                        // `e.current` is the current value of `self.pred`.
                        e.current
                    });

                // If the predecessor node is already marked as deleted, we need to restart from
                // `head`.
                if succ.tag() != 0 {
                    self.pred = self.head;
                    self.curr = self.head.load(Acquire, self.guard);

                    return Some(Err(IterError::Stalled));
                }

                // Move over the removed by only advancing `curr`, not `pred`.
                self.curr = succ;
                continue;
            }

            // Move one step forward.
            self.pred = &c.next;
            self.curr = succ;

            return Some(Ok(unsafe { C::element_of(c) }));
        }

        // We reached the end of the list.
        None
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crossbeam_utils::thread;
    use std::sync::Barrier;
    use {Collector, Owned};

    impl IsElement<Entry> for Entry {
        fn entry_of(entry: &Entry) -> &Entry {
            entry
        }

        unsafe fn element_of(entry: &Entry) -> &Entry {
            entry
        }

        unsafe fn finalize(entry: &Entry, guard: &Guard) {
            guard.defer_destroy(Shared::from(Self::element_of(entry) as *const _));
        }
    }

    /// Checks whether the list retains inserted elements
    /// and returns them in the correct order.
    #[test]
    fn insert() {
        let collector = Collector::new();
        let handle = collector.register();
        let guard = handle.pin();

        let l: List<Entry> = List::new();

        let e1 = Owned::new(Entry::default()).into_shared(&guard);
        let e2 = Owned::new(Entry::default()).into_shared(&guard);
        let e3 = Owned::new(Entry::default()).into_shared(&guard);

        unsafe {
            l.insert(e1, &guard);
            l.insert(e2, &guard);
            l.insert(e3, &guard);
        }

        let mut iter = l.iter(&guard);
        let maybe_e3 = iter.next();
        assert!(maybe_e3.is_some());
        assert!(maybe_e3.unwrap().unwrap() as *const Entry == e3.as_raw());
        let maybe_e2 = iter.next();
        assert!(maybe_e2.is_some());
        assert!(maybe_e2.unwrap().unwrap() as *const Entry == e2.as_raw());
        let maybe_e1 = iter.next();
        assert!(maybe_e1.is_some());
        assert!(maybe_e1.unwrap().unwrap() as *const Entry == e1.as_raw());
        assert!(iter.next().is_none());

        unsafe {
            e1.as_ref().unwrap().delete(&guard);
            e2.as_ref().unwrap().delete(&guard);
            e3.as_ref().unwrap().delete(&guard);
        }
    }

    /// Checks whether elements can be removed from the list and whether
    /// the correct elements are removed.
    #[test]
    fn delete() {
        let collector = Collector::new();
        let handle = collector.register();
        let guard = handle.pin();

        let l: List<Entry> = List::new();

        let e1 = Owned::new(Entry::default()).into_shared(&guard);
        let e2 = Owned::new(Entry::default()).into_shared(&guard);
        let e3 = Owned::new(Entry::default()).into_shared(&guard);
        unsafe {
            l.insert(e1, &guard);
            l.insert(e2, &guard);
            l.insert(e3, &guard);
            e2.as_ref().unwrap().delete(&guard);
        }

        let mut iter = l.iter(&guard);
        let maybe_e3 = iter.next();
        assert!(maybe_e3.is_some());
        assert!(maybe_e3.unwrap().unwrap() as *const Entry == e3.as_raw());
        let maybe_e1 = iter.next();
        assert!(maybe_e1.is_some());
        assert!(maybe_e1.unwrap().unwrap() as *const Entry == e1.as_raw());
        assert!(iter.next().is_none());

        unsafe {
            e1.as_ref().unwrap().delete(&guard);
            e3.as_ref().unwrap().delete(&guard);
        }

        let mut iter = l.iter(&guard);
        assert!(iter.next().is_none());
    }

    const THREADS: usize = 8;
    const ITERS: usize = 512;

    /// Contends the list on insert and delete operations to make sure they can run concurrently.
    #[test]
    fn insert_delete_multi() {
        let collector = Collector::new();

        let l: List<Entry> = List::new();
        let b = Barrier::new(THREADS);

        thread::scope(|s| {
            for _ in 0..THREADS {
                s.spawn(|_| {
                    b.wait();

                    let handle = collector.register();
                    let guard: Guard = handle.pin();
                    let mut v = Vec::with_capacity(ITERS);

                    for _ in 0..ITERS {
                        let e = Owned::new(Entry::default()).into_shared(&guard);
                        v.push(e);
                        unsafe {
                            l.insert(e, &guard);
                        }
                    }

                    for e in v {
                        unsafe {
                            e.as_ref().unwrap().delete(&guard);
                        }
                    }
                });
            }
        })
        .unwrap();

        let handle = collector.register();
        let guard = handle.pin();

        let mut iter = l.iter(&guard);
        assert!(iter.next().is_none());
    }

    /// Contends the list on iteration to make sure that it can be iterated over concurrently.
    #[test]
    fn iter_multi() {
        let collector = Collector::new();

        let l: List<Entry> = List::new();
        let b = Barrier::new(THREADS);

        thread::scope(|s| {
            for _ in 0..THREADS {
                s.spawn(|_| {
                    b.wait();

                    let handle = collector.register();
                    let guard: Guard = handle.pin();
                    let mut v = Vec::with_capacity(ITERS);

                    for _ in 0..ITERS {
                        let e = Owned::new(Entry::default()).into_shared(&guard);
                        v.push(e);
                        unsafe {
                            l.insert(e, &guard);
                        }
                    }

                    let mut iter = l.iter(&guard);
                    for _ in 0..ITERS {
                        assert!(iter.next().is_some());
                    }

                    for e in v {
                        unsafe {
                            e.as_ref().unwrap().delete(&guard);
                        }
                    }
                });
            }
        })
        .unwrap();

        let handle = collector.register();
        let guard = handle.pin();

        let mut iter = l.iter(&guard);
        assert!(iter.next().is_none());
    }
}
<|endoftext|>


<commit_before>extern crate git2;
const TMP_NAME: &'static str = "tmp_fd2db5f8_bac2_4a1e_9487_4ac3414788aa";

use git2::*;
use std::process::Command;
use std::path::Path;
use shell::Shell;
use super::RepoHost;
use std::collections::HashMap;

pub fn module_ref(module: &str) -> String
{
    format!("refs/centralgit/splited/{}/split", module)
}

pub struct Scratch<'a>
{
    pub repo: Repository,
    pub host: &'a RepoHost,
}

impl<'a> Scratch<'a>
{
    pub fn new(path: &Path, host: &'a RepoHost) -> Scratch<'a>
    {
        Scratch {
            repo: Repository::init_bare(&path).expect("could not init scratch"),
            host: host,
        }
    }

    pub fn tracking(&self, module: &str, branch: &str) -> Option<Object>
    {
        let remote_name = format!("{}", module);
        let fetch_url = self.host.local_path(&module);
        let mut remote = if let Ok(remote) = self.repo.find_remote(&remote_name) {
            remote
        }
        else {
            debug!("==== create remote (remote_name:{}, remote_url:{})",
                   &remote_name,
                   &fetch_url);
            self.repo.remote(&remote_name, &fetch_url).expect("can't create remote")
        };

        let rs = remote.get_refspec(0).unwrap().str().unwrap().to_string();
        if let Ok(_) = remote.fetch(&[&rs], None, None) {
            return self.repo
                .revparse_single(&format!("remotes/{}/{}", module, branch))
                .ok();
        }
        else {
            return None;
        }
    }

    fn call_git(self: &Scratch<'a>, cmd: &str) -> Result<String, Error>
    {
        let args: Vec<&str> = cmd.split(" ").collect();
        let repo_path = &self.repo.path();
        let mut c = Command::new("git");
        c.current_dir(&repo_path);
        c.env("GIT_DIR", repo_path.as_os_str());
        c.args(&args);

        let output = c.output()
            .unwrap_or_else(|e| panic!("failed to execute process: {}", e));
        Ok(String::from_utf8(output.stderr).expect("cannot decode utf8"))
    }

    // force push of the new revision-object to temp repo
    pub fn transfer(&self, rev: &str, source: &Path) -> Object
    {
        // TODO: implement using libgit
        let target = &self.repo.path();
        let shell = Shell { cwd: source.to_path_buf() };
        // create tmp branch
        shell.command(&format!("git branch -f {} {}", TMP_NAME, rev));
        // force push
        shell.command(&format!("git push --force {} {}",
                               &target.to_string_lossy(),
                               TMP_NAME));
        // delete tmp branch
        shell.command(&format!("git branch -D {}", TMP_NAME));

        let obj = self.repo.revparse_single(rev).expect("can't find transfered ref");
        return obj;
    }

    // takes everything from base except it's tree and replaces it with the tree
    // given
    pub fn rewrite(&self, base: &Commit, parents: &[&Commit], tree: &Tree) -> Oid
    {
        if parents.len() == 0 {
            ::std::fs::remove_file(self.repo.path().join("HEAD")).expect("can't remove HEAD");
        }
        else {
            self.repo.set_head_detached(parents[0].id()).expect("rewrite: can't detach head");
        }
        self.repo
            .commit(Some("HEAD"),
                    &base.author(),
                    &base.committer(),
                    &base.message().unwrap_or("no message"),
                    tree,
                    parents)
            .expect("rewrite: can't commit")
    }

    pub fn push(&self, oid: Oid, module: &str, target: &str) -> String
    {
        let commit = &self.repo.find_commit(oid).expect("can't find commit");
        self.repo.set_head_detached(commit.id()).expect("can't detach HEAD");
        let cmd = format!("push {} HEAD:{}", self.host.remote_url(module), target);
        let output = self.call_git(&cmd).expect("can't push");
        debug!("push: {}\n{}", cmd, output);
        format!("{}", output)
    }

    fn subtree(&self, tree: &Tree, path: &Path) -> Option<Tree>
    {
        if let Some(oid) = tree.get_path(path).map(|x| x.id()).ok() {
            return self.repo.find_tree(oid).ok();
        }
        else {
            return None;
        }
    }

    fn replace_child(&self, child: &Path, subtree: Oid, full_tree: Tree) -> Tree
    {
        let full_tree_id = {
            let mut builder = self.repo
                .treebuilder(Some(&full_tree))
                .expect("replace_child: can't create treebuilder");
            builder.insert(child, subtree, 0o0040000) // GIT_FILEMODE_TREE
                .expect("replace_child: can't insert tree");
            builder.write().expect("replace_child: can't write tree")
        };
        return self.repo.find_tree(full_tree_id).expect("replace_child: can't find new tree");
    }

    pub fn replace_subtree(&self, path: &Path, subtree: Oid, full_tree: Tree) -> Tree
    {
        if path.components().count() == 1 {
            return self.replace_child(path, subtree, full_tree);
        }
        else {
            let name = Path::new(path.file_name().expect("no module name"));
            let path = path.parent().expect("module not in subdir");

            let st = self.subtree(&full_tree, path).unwrap();
            let tree = self.replace_child(name, subtree, st);

            return self.replace_subtree(path, tree.id(), full_tree);
        }
    }

    pub fn split_subdir(&self, module: &str, newrev: Oid) -> Option<Oid>
    {
        let walk = {
            let mut walk = self.repo.revwalk().expect("walk: can't create revwalk");
            walk.set_sorting(SORT_REVERSE | SORT_TOPOLOGICAL);
            walk.push(newrev).expect("walk.push");
            walk
        };

        let mut map = HashMap::<Oid, Oid>::new();

        'walk: for commit in walk {
            let commit = self.repo.find_commit(commit.unwrap()).unwrap();
            let tree = commit.tree().expect("commit has no tree");

            let new_tree = if let Ok(tree_entry) = tree.get_path(&Path::new(&module)) {
                self.repo.find_tree(tree_entry.id()).expect("central_submit: can't find tree")
            }
            else {
                continue 'walk;
            };

            match commit.parents().count() {
                2 => {
                    let parent1 = commit.parents().nth(0).unwrap().id();
                    let parent2 = commit.parents().nth(1).unwrap().id();
                    if let (Some(&parent1), Some(&parent2)) = (map.get(&parent1),
                                                               map.get(&parent2)) {
                        let parent1 = self.repo.find_commit(parent1).unwrap();
                        let parent2 = self.repo.find_commit(parent2).unwrap();

                        let new = new_tree.id();
                        let p1 = parent1.tree().unwrap().id();
                        let p2 = parent2.tree().unwrap().id();

                        // if new != p1 && new != p2 {
                        //     map.insert(commit.id(),
                        //                self.rewrite(&commit, &[&parent1, &parent2], &new_tree));
                        //     continue 'walk;
                        // }

                        // if new == p1 && new != p2 {
                        //     map.insert(commit.id(),
                        //                self.rewrite(&commit, &[&parent1, &parent2], &new_tree));
                        //     continue 'walk;
                        // }

                        // if new != p1 && new == p2 {
                            map.insert(commit.id(),
                                       self.rewrite(&commit, &[&parent1, &parent2], &new_tree));
                            continue 'walk;
                        // }

                        // if new == p1 && new == p2 {
                        //     map.insert(commit.id(),
                        //                self.rewrite(&commit, &[&parent1, &parent2], &new_tree));
                        //     continue 'walk;
                        // }

                        // if new_tree.id() == parent1.tree().unwrap().id() {
                        //     map.insert(commit.id(), parent1.id());
                        //     continue 'walk;
                        // }
                        // if new_tree.id() == parent2.tree().unwrap().id() {
                        //     map.insert(commit.id(), parent2.id());
                        //     continue 'walk;
                        // }
                        // map.insert(commit.id(),
                        //            self.rewrite(&commit, &[&parent1, &parent2], &new_tree));
                        // continue 'walk;
                    }
                }
                1 => {
                    let parent = commit.parents().nth(0).unwrap().id();
                    if let Some(&parent) = map.get(&parent) {
                        let parent = self.repo.find_commit(parent).unwrap();
                        if new_tree.id() == parent.tree().unwrap().id() {
                            map.insert(commit.id(), parent.id());
                            continue 'walk;
                        }
                        map.insert(commit.id(), self.rewrite(&commit, &[&parent], &new_tree));
                        continue 'walk;
                    }
                }
                _ => {}
            }

            map.insert(commit.id(), self.rewrite(&commit, &[], &new_tree));
        }

        return map.get(&newrev).map(|&id| id);
    }

    pub fn find_all_subdirs(&self, tree: &Tree) -> Vec<String>
    {
        let mut sd = vec![];
        for item in tree {
            if let Ok(st) = self.repo.find_tree(item.id()) {
                let name = item.name().unwrap();
                if !name.starts_with(".") {
                    sd.push(name.to_string());
                    for r in self.find_all_subdirs(&st) {
                        sd.push(format!("{}/{}", name, r));
                    }
                }
            }
        }
        return sd;
    }
}
<commit_msg>remove call_git function<commit_after>extern crate git2;
const TMP_NAME: &'static str = "tmp_fd2db5f8_bac2_4a1e_9487_4ac3414788aa";

use git2::*;
use std::process::Command;
use std::path::Path;
use shell::Shell;
use super::RepoHost;
use std::collections::HashMap;

pub fn module_ref(module: &str) -> String
{
    format!("refs/centralgit/splited/{}/split", module)
}

pub struct Scratch<'a>
{
    pub repo: Repository,
    pub host: &'a RepoHost,
}

impl<'a> Scratch<'a>
{
    pub fn new(path: &Path, host: &'a RepoHost) -> Scratch<'a>
    {
        Scratch {
            repo: Repository::init_bare(&path).expect("could not init scratch"),
            host: host,
        }
    }

    pub fn tracking(&self, module: &str, branch: &str) -> Option<Object>
    {
        let remote_name = format!("{}", module);
        let fetch_url = self.host.local_path(&module);
        let mut remote = if let Ok(remote) = self.repo.find_remote(&remote_name) {
            remote
        }
        else {
            debug!("==== create remote (remote_name:{}, remote_url:{})",
                   &remote_name,
                   &fetch_url);
            self.repo.remote(&remote_name, &fetch_url).expect("can't create remote")
        };

        let rs = remote.get_refspec(0).unwrap().str().unwrap().to_string();
        if let Ok(_) = remote.fetch(&[&rs], None, None) {
            return self.repo
                .revparse_single(&format!("remotes/{}/{}", module, branch))
                .ok();
        }
        else {
            return None;
        }
    }

    // force push of the new revision-object to temp repo
    pub fn transfer(&self, rev: &str, source: &Path) -> Object
    {
        // TODO: implement using libgit
        let target = &self.repo.path();
        let shell = Shell { cwd: source.to_path_buf() };
        // create tmp branch
        shell.command(&format!("git branch -f {} {}", TMP_NAME, rev));
        // force push
        shell.command(&format!("git push --force {} {}",
                               &target.to_string_lossy(),
                               TMP_NAME));
        // delete tmp branch
        shell.command(&format!("git branch -D {}", TMP_NAME));

        let obj = self.repo.revparse_single(rev).expect("can't find transfered ref");
        return obj;
    }

    // takes everything from base except it's tree and replaces it with the tree
    // given
    pub fn rewrite(&self, base: &Commit, parents: &[&Commit], tree: &Tree) -> Oid
    {
        if parents.len() == 0 {
            ::std::fs::remove_file(self.repo.path().join("HEAD")).expect("can't remove HEAD");
        }
        else {
            self.repo.set_head_detached(parents[0].id()).expect("rewrite: can't detach head");
        }
        self.repo
            .commit(Some("HEAD"),
                    &base.author(),
                    &base.committer(),
                    &base.message().unwrap_or("no message"),
                    tree,
                    parents)
            .expect("rewrite: can't commit")
    }

    pub fn push(&self, oid: Oid, module: &str, target: &str) -> String
    {
        let commit = &self.repo.find_commit(oid).expect("can't find commit");
        self.repo.set_head_detached(commit.id()).expect("can't detach HEAD");
        let cmd = format!("git push {} HEAD:{}", self.host.remote_url(module), target);
        let shell = Shell { cwd: self.repo.path().to_path_buf() };
        let output = shell.command(&cmd);
        debug!("push: {}\n{}", cmd, output);
        format!("{}", output)
    }

    fn subtree(&self, tree: &Tree, path: &Path) -> Option<Tree>
    {
        if let Some(oid) = tree.get_path(path).map(|x| x.id()).ok() {
            return self.repo.find_tree(oid).ok();
        }
        else {
            return None;
        }
    }

    fn replace_child(&self, child: &Path, subtree: Oid, full_tree: Tree) -> Tree
    {
        let full_tree_id = {
            let mut builder = self.repo
                .treebuilder(Some(&full_tree))
                .expect("replace_child: can't create treebuilder");
            builder.insert(child, subtree, 0o0040000) // GIT_FILEMODE_TREE
                .expect("replace_child: can't insert tree");
            builder.write().expect("replace_child: can't write tree")
        };
        return self.repo.find_tree(full_tree_id).expect("replace_child: can't find new tree");
    }

    pub fn replace_subtree(&self, path: &Path, subtree: Oid, full_tree: Tree) -> Tree
    {
        if path.components().count() == 1 {
            return self.replace_child(path, subtree, full_tree);
        }
        else {
            let name = Path::new(path.file_name().expect("no module name"));
            let path = path.parent().expect("module not in subdir");

            let st = self.subtree(&full_tree, path).unwrap();
            let tree = self.replace_child(name, subtree, st);

            return self.replace_subtree(path, tree.id(), full_tree);
        }
    }

    pub fn split_subdir(&self, module: &str, newrev: Oid) -> Option<Oid>
    {
        let walk = {
            let mut walk = self.repo.revwalk().expect("walk: can't create revwalk");
            walk.set_sorting(SORT_REVERSE | SORT_TOPOLOGICAL);
            walk.push(newrev).expect("walk.push");
            walk
        };

        let mut map = HashMap::<Oid, Oid>::new();

        'walk: for commit in walk {
            let commit = self.repo.find_commit(commit.unwrap()).unwrap();
            let tree = commit.tree().expect("commit has no tree");

            let new_tree = if let Ok(tree_entry) = tree.get_path(&Path::new(&module)) {
                self.repo.find_tree(tree_entry.id()).expect("central_submit: can't find tree")
            }
            else {
                continue 'walk;
            };

            match commit.parents().count() {
                2 => {
                    let parent1 = commit.parents().nth(0).unwrap().id();
                    let parent2 = commit.parents().nth(1).unwrap().id();
                    if let (Some(&parent1), Some(&parent2)) = (map.get(&parent1),
                                                               map.get(&parent2)) {
                        let parent1 = self.repo.find_commit(parent1).unwrap();
                        let parent2 = self.repo.find_commit(parent2).unwrap();

                        let new = new_tree.id();
                        let p1 = parent1.tree().unwrap().id();
                        let p2 = parent2.tree().unwrap().id();

                        // if new != p1 && new != p2 {
                        //     map.insert(commit.id(),
                        //                self.rewrite(&commit, &[&parent1, &parent2], &new_tree));
                        //     continue 'walk;
                        // }

                        // if new == p1 && new != p2 {
                        //     map.insert(commit.id(),
                        //                self.rewrite(&commit, &[&parent1, &parent2], &new_tree));
                        //     continue 'walk;
                        // }

                        // if new != p1 && new == p2 {
                            map.insert(commit.id(),
                                       self.rewrite(&commit, &[&parent1, &parent2], &new_tree));
                            continue 'walk;
                        // }

                        // if new == p1 && new == p2 {
                        //     map.insert(commit.id(),
                        //                self.rewrite(&commit, &[&parent1, &parent2], &new_tree));
                        //     continue 'walk;
                        // }

                        // if new_tree.id() == parent1.tree().unwrap().id() {
                        //     map.insert(commit.id(), parent1.id());
                        //     continue 'walk;
                        // }
                        // if new_tree.id() == parent2.tree().unwrap().id() {
                        //     map.insert(commit.id(), parent2.id());
                        //     continue 'walk;
                        // }
                        // map.insert(commit.id(),
                        //            self.rewrite(&commit, &[&parent1, &parent2], &new_tree));
                        // continue 'walk;
                    }
                }
                1 => {
                    let parent = commit.parents().nth(0).unwrap().id();
                    if let Some(&parent) = map.get(&parent) {
                        let parent = self.repo.find_commit(parent).unwrap();
                        if new_tree.id() == parent.tree().unwrap().id() {
                            map.insert(commit.id(), parent.id());
                            continue 'walk;
                        }
                        map.insert(commit.id(), self.rewrite(&commit, &[&parent], &new_tree));
                        continue 'walk;
                    }
                }
                _ => {}
            }

            map.insert(commit.id(), self.rewrite(&commit, &[], &new_tree));
        }

        return map.get(&newrev).map(|&id| id);
    }

    pub fn find_all_subdirs(&self, tree: &Tree) -> Vec<String>
    {
        let mut sd = vec![];
        for item in tree {
            if let Ok(st) = self.repo.find_tree(item.id()) {
                let name = item.name().unwrap();
                if !name.starts_with(".") {
                    sd.push(name.to_string());
                    for r in self.find_all_subdirs(&st) {
                        sd.push(format!("{}/{}", name, r));
                    }
                }
            }
        }
        return sd;
    }
}
<|endoftext|>


<commit_before>use std::env;
use std::path::Path;
use std::string::String;

lazy_static! {
    static ref DEFAULT_CONF_PATH_STR: String = String::from("/etc/sectora.conf");
    static ref CONF_PATH_STR: String = env::var("SECTORA_CONFIG").unwrap_or(DEFAULT_CONF_PATH_STR.clone());
    pub static ref CONF_PATH: &'static Path = Path::new(&(*CONF_PATH_STR));
}

pub const TEMP_DIRNAME: &str = "sectora-cache";
<commit_msg>Use &str for static<commit_after>use std::env;
use std::path::Path;
use std::string::String;

const DEFAULT_CONF_PATH_STR: &str = "/etc/sectora.conf";
pub const TEMP_DIRNAME: &str = "sectora-cache";

lazy_static! {
    static ref CONF_PATH_STR: String = env::var("SECTORA_CONFIG").unwrap_or(String::from(DEFAULT_CONF_PATH_STR));
    pub static ref CONF_PATH: &'static Path = Path::new(&(*CONF_PATH_STR));
}
<|endoftext|>


<commit_before>use raft::raftpb::*;
use raft::errors::Result;

#[derive(Debug, Clone)]
pub struct RaftState {
    hard_state: HardState,
    conf_state: ConfState,
}

pub trait Storage {
    fn initial_state() -> Result<RaftState>;
    fn entries(low: u64, high: u64, max_size: u64) -> Vec<Entry>;
    fn term(idx: u64) -> Result<u64>;
    fn first_index() -> Result<u64>;
    fn last_index() -> Result<u64>;
    fn snapshot() -> Result<Snapshot>;
}

pub struct MemStorage {
    hard_state: HardState,
    snapshot: Snapshot,
    entries: Vec<Entry>,
}

// pub fn new() -> MemStorage {
// MemStorage { entries: Vec::new() }
// }
//

impl Storage for MemStorage {
    fn initial_state() -> Result<RaftState> {
        None
    }

    fn entries(low: u64, high: u64, max_size: u64) -> Vec<Entry> {
        None
    }

    fn term(idx: u64) -> Result<u64> {
        None
    }

    fn first_index() -> Result<u64> {
        None
    }

    fn last_index() -> Result<u64> {
        None
    }

    fn snapshot() -> Result<Snapshot> {
        None
    }
}
<commit_msg>Implement more methods<commit_after>use raft::raftpb::*;
use raft::errors::Result;

#[derive(Debug, Clone)]
pub struct RaftState {
    hard_state: HardState,
    conf_state: ConfState,
}

pub trait Storage {
    fn initial_state() -> Result<RaftState>;
    fn entries(low: u64, high: u64, max_size: u64) -> Vec<Entry>;
    fn term(idx: u64) -> Result<u64>;
    fn first_index() -> Result<u64>;
    fn last_index() -> Result<u64>;
    fn snapshot() -> Result<Snapshot>;
}

pub struct MemStorage {
    hard_state: HardState,
    snapshot: Snapshot,
    entries: Vec<Entry>,
}

impl MemStorage {
    pub fn new() -> MemStorage {
	MemStorage {
	    entries: vec![Entry::new()],
	    hard_state:HardState::new(),
	    snapshot:Snapshot::new(),
	}
    }
}

impl Storage for MemStorage {
    fn initial_state() -> Result<RaftState> {
	unimplemented!()
    }

    fn entries(low: u64, high: u64, max_size: u64) -> Vec<Entry> {
	unimplemented!()
    }

    fn term(idx: u64) -> Result<u64> {
	unimplemented!()
    }

    fn first_index() -> Result<u64> {
	unimplemented!()
    }

    fn last_index() -> Result<u64> {
	unimplemented!()
    }

    fn snapshot() -> Result<Snapshot> {
	unimplemented!()
    }
}
<|endoftext|>


<commit_before>use rutorch::*;
use std::ops::{Index, IndexMut};
use std::slice;

macro_rules! impl_storage_impl {
    ($name:ident, $type:ident, $thname:ident) => {
        pub struct $name {
            pub t: *mut $thname,
        }
        impl Clone for $name {
            fn clone(&self) -> Self {
                unsafe { concat_idents!($thname, _retain)(self.t)};
                $name {t: self.t }
            }
        }
        impl $name {
            pub fn new() -> Self {
                unsafe { $name { t: concat_idents!($thname, _new)() } }
            }
            pub fn with_capacity(size: usize) -> Self {
                unsafe { $name { t: concat_idents!($thname, _newWithSize)(size as isize) } }
            }
            pub fn with_data<D>(data: D) -> Self
                where D: AsRef<[$type]>
            {
                let data = data.as_ref();
                let mut store = unsafe { $name {
                    t: concat_idents!($thname, _newWithSize)(data.len() as isize)
                } };
                for i in 0..data.len() {
                    store[i as isize] = data[i];
                }
                store
            }
            pub fn into_slice(&self) -> &[$type] {
                unsafe { slice::from_raw_parts((*self.t).data, (*self.t).size as usize) }
            }
            pub fn into_slice_mut(&mut self) -> &mut [$type] {
                unsafe { slice::from_raw_parts_mut((*self.t).data, (*self.t).size as usize) }
            }
            pub fn iter(&self) -> slice::Iter<$type> {
                self.into_slice().iter()
            }
            pub fn iter_mut(&mut self) -> slice::IterMut<$type> {
                self.into_slice_mut().iter_mut()
            }
        }
        impl Drop for $name {
            fn drop(&mut self) {
                unsafe { concat_idents!($thname, _free)(self.t) }
            }
        }
        impl Index<isize> for $name {
            type Output = $type;
            fn index(&self, idx: isize) -> &Self::Output {
                unsafe { &*(*self.t).data.offset(idx) }
            }
        }
        impl IndexMut<isize> for $name {
            fn index_mut(&mut self, idx: isize) -> &mut Self::Output {
                unsafe { &mut *(*self.t).data.offset(idx) }
            }
        }
    }
}

impl_storage_impl!(FloatStorage, f32, THFloatStorage);
impl_storage_impl!(DoubleStorage, f64, THDoubleStorage);
impl_storage_impl!(LongStorage, i64, THLongStorage);
impl_storage_impl!(ByteStorage, u8, THByteStorage);
<commit_msg>export length<commit_after>use rutorch::*;
use std::ops::{Index, IndexMut};
use std::slice;

macro_rules! impl_storage_impl {
    ($name:ident, $type:ident, $thname:ident) => {
        pub struct $name {
            pub t: *mut $thname,
        }
        impl Clone for $name {
            fn clone(&self) -> Self {
                unsafe { concat_idents!($thname, _retain)(self.t)};
                $name {t: self.t }
            }
        }
        impl $name {
            pub fn new() -> Self {
                unsafe { $name { t: concat_idents!($thname, _new)() } }
            }
            pub fn len(&self) -> usize {
                let t = unsafe {(*self.t).size };
                t as usize
            }
            pub fn with_capacity(size: usize) -> Self {
                unsafe { $name { t: concat_idents!($thname, _newWithSize)(size as isize) } }
            }
            pub fn with_data<D>(data: D) -> Self
                where D: AsRef<[$type]>
            {
                let data = data.as_ref();
                let mut store = unsafe { $name {
                    t: concat_idents!($thname, _newWithSize)(data.len() as isize)
                } };
                for i in 0..data.len() {
                    store[i as isize] = data[i];
                }
                store
            }
            pub fn into_slice(&self) -> &[$type] {
                unsafe { slice::from_raw_parts((*self.t).data, (*self.t).size as usize) }
            }
            pub fn into_slice_mut(&mut self) -> &mut [$type] {
                unsafe { slice::from_raw_parts_mut((*self.t).data, (*self.t).size as usize) }
            }
            pub fn iter(&self) -> slice::Iter<$type> {
                self.into_slice().iter()
            }
            pub fn iter_mut(&mut self) -> slice::IterMut<$type> {
                self.into_slice_mut().iter_mut()
            }
        }
        impl Drop for $name {
            fn drop(&mut self) {
                unsafe { concat_idents!($thname, _free)(self.t) }
            }
        }
        impl Index<isize> for $name {
            type Output = $type;
            fn index(&self, idx: isize) -> &Self::Output {
                unsafe { &*(*self.t).data.offset(idx) }
            }
        }
        impl IndexMut<isize> for $name {
            fn index_mut(&mut self, idx: isize) -> &mut Self::Output {
                unsafe { &mut *(*self.t).data.offset(idx) }
            }
        }
    }
}

impl_storage_impl!(FloatStorage, f32, THFloatStorage);
impl_storage_impl!(DoubleStorage, f64, THDoubleStorage);
impl_storage_impl!(LongStorage, i64, THLongStorage);
impl_storage_impl!(ByteStorage, u8, THByteStorage);
<|endoftext|>


<commit_before>use std::rc::Weak;
use traits::*;

pub struct ObservableValue<T: PartialEq, O: Observer<Observes = T>> {
    observables: Vec<Weak<O>>,
    value: T,
}

impl<T: PartialEq, O: Observer<Observes = T>> ObservableValue<T, O> {
    pub fn new(value: T) -> ObservableValue<T, O> {
        ObservableValue {
            observables: vec![],
            value: value,
        }
    }

    pub fn clean(&mut self) {
        self.observables.retain(|o| o.upgrade().is_some());
    }

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

impl<T: PartialEq, O: Observer<Observes = T>> Observable<O> for ObservableValue<T, O> {
    type Has = T;

    fn register(&mut self, observer: Weak<O>) {
        self.observables.push(observer);
    }

    fn set_silently(&mut self, data: T) {
        self.value = data;
    }

    fn peek(&self) -> &T {
        &self.value
    }

    fn trigger(&mut self) {
        self.clean();

        for o in &self.observables {
            match o.upgrade() {
                Some(o) => o.update(&self.value),
                _ => (),
            }
        }
    }
}<commit_msg>Replaced one-armed match statement with if let<commit_after>use std::rc::Weak;
use traits::*;

pub struct ObservableValue<T: PartialEq, O: Observer<Observes = T>> {
    observables: Vec<Weak<O>>,
    value: T,
}

impl<T: PartialEq, O: Observer<Observes = T>> ObservableValue<T, O> {
    pub fn new(value: T) -> ObservableValue<T, O> {
        ObservableValue {
            observables: vec![],
            value: value,
        }
    }

    pub fn clean(&mut self) {
        self.observables.retain(|o| o.upgrade().is_some());
    }

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

impl<T: PartialEq, O: Observer<Observes = T>> Observable<O> for ObservableValue<T, O> {
    type Has = T;

    fn register(&mut self, observer: Weak<O>) {
        self.observables.push(observer);
    }

    fn set_silently(&mut self, data: T) {
        self.value = data;
    }

    fn peek(&self) -> &T {
        &self.value
    }

    fn trigger(&mut self) {
        self.clean();

        for o in &self.observables {
            if let Some(o) = o.upgrade() {
                o.update(&self.value);
            }
        }
    }
}<|endoftext|>