<commit_before>use rustc_middle::mir;

use crate::*;
use helpers::check_arg_count;

#[derive(Debug, Copy, Clone)]
pub enum Dlsym {
    GetEntropy,
}

impl Dlsym {
    // Returns an error for unsupported symbols, and None if this symbol
    // should become a NULL pointer (pretend it does not exist).
    pub fn from_str(name: &[u8], target_os: &str) -> InterpResult<'static, Option<Dlsym>> {
        use self::Dlsym::*;
        let name = String::from_utf8_lossy(name);
        Ok(match target_os {
            "linux" => match &*name {
                "__pthread_get_minstack" => None,
                _ => throw_unsup_format!("unsupported Linux dlsym: {}", name),
            }
            "macos" => match &*name {
                "getentropy" => Some(GetEntropy),
                _ => throw_unsup_format!("unsupported macOS dlsym: {}", name),
            }
            "windows" => match &*name {
                "SetThreadStackGuarantee" => None,
                "AcquireSRWLockExclusive" => None,
                _ => throw_unsup_format!("unsupported Windows dlsym: {}", name),
            }
            os => bug!("dlsym not implemented for target_os {}", os),
        })
    }
}

impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
    fn call_dlsym(
        &mut self,
        dlsym: Dlsym,
        args: &[OpTy<'tcx, Tag>],
        ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>,
    ) -> InterpResult<'tcx> {
        use self::Dlsym::*;

        let this = self.eval_context_mut();
        let (dest, ret) = ret.expect("we don't support any diverging dlsym");

        match dlsym {
            GetEntropy => {
                let &[ptr, len] = check_arg_count(args)?;
                let ptr = this.read_scalar(ptr)?.not_undef()?;
                let len = this.read_scalar(len)?.to_machine_usize(this)?;
                this.gen_random(ptr, len)?;
                this.write_null(dest)?;
            }
        }

        this.dump_place(*dest);
        this.go_to_block(ret);
        Ok(())
    }
}
<commit_msg>also pretend GetSystemTimePreciseAsFileTime does not exist<commit_after>use rustc_middle::mir;

use crate::*;
use helpers::check_arg_count;

#[derive(Debug, Copy, Clone)]
pub enum Dlsym {
    GetEntropy,
}

impl Dlsym {
    // Returns an error for unsupported symbols, and None if this symbol
    // should become a NULL pointer (pretend it does not exist).
    pub fn from_str(name: &[u8], target_os: &str) -> InterpResult<'static, Option<Dlsym>> {
        use self::Dlsym::*;
        let name = String::from_utf8_lossy(name);
        Ok(match target_os {
            "linux" => match &*name {
                "__pthread_get_minstack" => None,
                _ => throw_unsup_format!("unsupported Linux dlsym: {}", name),
            }
            "macos" => match &*name {
                "getentropy" => Some(GetEntropy),
                _ => throw_unsup_format!("unsupported macOS dlsym: {}", name),
            }
            "windows" => match &*name {
                "SetThreadStackGuarantee" => None,
                "AcquireSRWLockExclusive" => None,
                "GetSystemTimePreciseAsFileTime" => None,
                _ => throw_unsup_format!("unsupported Windows dlsym: {}", name),
            }
            os => bug!("dlsym not implemented for target_os {}", os),
        })
    }
}

impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
    fn call_dlsym(
        &mut self,
        dlsym: Dlsym,
        args: &[OpTy<'tcx, Tag>],
        ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>,
    ) -> InterpResult<'tcx> {
        use self::Dlsym::*;

        let this = self.eval_context_mut();
        let (dest, ret) = ret.expect("we don't support any diverging dlsym");

        match dlsym {
            GetEntropy => {
                let &[ptr, len] = check_arg_count(args)?;
                let ptr = this.read_scalar(ptr)?.not_undef()?;
                let len = this.read_scalar(len)?.to_machine_usize(this)?;
                this.gen_random(ptr, len)?;
                this.write_null(dest)?;
            }
        }

        this.dump_place(*dest);
        this.go_to_block(ret);
        Ok(())
    }
}
<|endoftext|>


<commit_before>//! See `CompletionItem` structure.

use std::fmt;

use hir::{Documentation, Mutability};
use ide_db::{
    helpers::{
        import_assets::LocatedImport,
        insert_use::{self, ImportScope, InsertUseConfig},
        mod_path_to_ast, SnippetCap,
    },
    SymbolKind,
};
use stdx::{format_to, impl_from, never};
use syntax::{algo, TextRange};
use text_edit::TextEdit;

/// `CompletionItem` describes a single completion variant in the editor pop-up.
/// It is basically a POD with various properties. To construct a
/// `CompletionItem`, use `new` method and the `Builder` struct.
#[derive(Clone)]
pub struct CompletionItem {
    /// Used only internally in tests, to check only specific kind of
    /// completion (postfix, keyword, reference, etc).
    #[allow(unused)]
    pub(crate) completion_kind: CompletionKind,
    /// Label in the completion pop up which identifies completion.
    label: String,
    /// Range of identifier that is being completed.
    ///
    /// It should be used primarily for UI, but we also use this to convert
    /// genetic TextEdit into LSP's completion edit (see conv.rs).
    ///
    /// `source_range` must contain the completion offset. `insert_text` should
    /// start with what `source_range` points to, or VSCode will filter out the
    /// completion silently.
    source_range: TextRange,
    /// What happens when user selects this item.
    ///
    /// Typically, replaces `source_range` with new identifier.
    text_edit: TextEdit,

    insert_text_format: InsertTextFormat,

    /// What item (struct, function, etc) are we completing.
    kind: Option<CompletionItemKind>,

    /// Lookup is used to check if completion item indeed can complete current
    /// ident.
    ///
    /// That is, in `foo.bar$0` lookup of `abracadabra` will be accepted (it
    /// contains `bar` sub sequence), and `quux` will rejected.
    lookup: Option<String>,

    /// Additional info to show in the UI pop up.
    detail: Option<String>,
    documentation: Option<Documentation>,

    /// Whether this item is marked as deprecated
    deprecated: bool,

    /// If completing a function call, ask the editor to show parameter popup
    /// after completion.
    trigger_call_info: bool,

    /// Score is useful to pre select or display in better order completion items
    score: Option<CompletionScore>,

    /// Indicates that a reference or mutable reference to this variable is a
    /// possible match.
    ref_match: Option<(Mutability, CompletionScore)>,

    /// The import data to add to completion's edits.
    import_to_add: Option<ImportEdit>,
}

// We use custom debug for CompletionItem to make snapshot tests more readable.
impl fmt::Debug for CompletionItem {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut s = f.debug_struct("CompletionItem");
        s.field("label", &self.label()).field("source_range", &self.source_range());
        if self.text_edit().len() == 1 {
            let atom = &self.text_edit().iter().next().unwrap();
            s.field("delete", &atom.delete);
            s.field("insert", &atom.insert);
        } else {
            s.field("text_edit", &self.text_edit);
        }
        if let Some(kind) = self.kind().as_ref() {
            s.field("kind", kind);
        }
        if self.lookup() != self.label() {
            s.field("lookup", &self.lookup());
        }
        if let Some(detail) = self.detail() {
            s.field("detail", &detail);
        }
        if let Some(documentation) = self.documentation() {
            s.field("documentation", &documentation);
        }
        if self.deprecated {
            s.field("deprecated", &true);
        }
        if let Some(score) = &self.score {
            s.field("score", score);
        }
        if self.trigger_call_info {
            s.field("trigger_call_info", &true);
        }
        s.finish()
    }
}

#[derive(Debug, Clone, Copy, Ord, PartialOrd, Eq, PartialEq)]
pub enum CompletionScore {
    /// If only type match
    TypeMatch,
    /// If type and name match
    TypeAndNameMatch,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CompletionItemKind {
    SymbolKind(SymbolKind),
    Attribute,
    Binding,
    BuiltinType,
    Keyword,
    Method,
    Snippet,
    UnresolvedReference,
}

impl_from!(SymbolKind for CompletionItemKind);

impl CompletionItemKind {
    #[cfg(test)]
    pub(crate) fn tag(&self) -> &'static str {
        match self {
            CompletionItemKind::SymbolKind(kind) => match kind {
                SymbolKind::Const => "ct",
                SymbolKind::ConstParam => "cp",
                SymbolKind::Enum => "en",
                SymbolKind::Field => "fd",
                SymbolKind::Function => "fn",
                SymbolKind::Impl => "im",
                SymbolKind::Label => "lb",
                SymbolKind::LifetimeParam => "lt",
                SymbolKind::Local => "lc",
                SymbolKind::Macro => "ma",
                SymbolKind::Module => "md",
                SymbolKind::SelfParam => "sp",
                SymbolKind::Static => "sc",
                SymbolKind::Struct => "st",
                SymbolKind::Trait => "tt",
                SymbolKind::TypeAlias => "ta",
                SymbolKind::TypeParam => "tp",
                SymbolKind::Union => "un",
                SymbolKind::ValueParam => "vp",
                SymbolKind::Variant => "ev",
            },
            CompletionItemKind::Attribute => "at",
            CompletionItemKind::Binding => "bn",
            CompletionItemKind::BuiltinType => "bt",
            CompletionItemKind::Keyword => "kw",
            CompletionItemKind::Method => "me",
            CompletionItemKind::Snippet => "sn",
            CompletionItemKind::UnresolvedReference => "??",
        }
    }
}

#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub(crate) enum CompletionKind {
    /// Parser-based keyword completion.
    Keyword,
    /// Your usual "complete all valid identifiers".
    Reference,
    /// "Secret sauce" completions.
    Magic,
    Snippet,
    Postfix,
    BuiltinType,
    Attribute,
}

#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum InsertTextFormat {
    PlainText,
    Snippet,
}

impl CompletionItem {
    pub(crate) fn new(
        completion_kind: CompletionKind,
        source_range: TextRange,
        label: impl Into<String>,
    ) -> Builder {
        let label = label.into();
        Builder {
            source_range,
            completion_kind,
            label,
            insert_text: None,
            insert_text_format: InsertTextFormat::PlainText,
            detail: None,
            documentation: None,
            lookup: None,
            kind: None,
            text_edit: None,
            deprecated: None,
            trigger_call_info: None,
            score: None,
            ref_match: None,
            import_to_add: None,
        }
    }

    /// What user sees in pop-up in the UI.
    pub fn label(&self) -> &str {
        &self.label
    }
    pub fn source_range(&self) -> TextRange {
        self.source_range
    }

    pub fn insert_text_format(&self) -> InsertTextFormat {
        self.insert_text_format
    }

    pub fn text_edit(&self) -> &TextEdit {
        &self.text_edit
    }

    /// Short one-line additional information, like a type
    pub fn detail(&self) -> Option<&str> {
        self.detail.as_deref()
    }
    /// A doc-comment
    pub fn documentation(&self) -> Option<Documentation> {
        self.documentation.clone()
    }
    /// What string is used for filtering.
    pub fn lookup(&self) -> &str {
        self.lookup.as_deref().unwrap_or(&self.label)
    }

    pub fn kind(&self) -> Option<CompletionItemKind> {
        self.kind
    }

    pub fn deprecated(&self) -> bool {
        self.deprecated
    }

    pub fn score(&self) -> Option<CompletionScore> {
        self.score
    }

    pub fn trigger_call_info(&self) -> bool {
        self.trigger_call_info
    }

    pub fn ref_match(&self) -> Option<(Mutability, CompletionScore)> {
        self.ref_match
    }

    pub fn import_to_add(&self) -> Option<&ImportEdit> {
        self.import_to_add.as_ref()
    }
}

/// An extra import to add after the completion is applied.
#[derive(Debug, Clone)]
pub struct ImportEdit {
    pub import: LocatedImport,
    pub scope: ImportScope,
}

impl ImportEdit {
    /// Attempts to insert the import to the given scope, producing a text edit.
    /// May return no edit in edge cases, such as scope already containing the import.
    pub fn to_text_edit(&self, cfg: InsertUseConfig) -> Option<TextEdit> {
        let _p = profile::span("ImportEdit::to_text_edit");

        let rewriter = insert_use::insert_use(
            &self.scope,
            mod_path_to_ast(&self.import.import_path),
            cfg,
        );
        let old_ast = rewriter.rewrite_root()?;
        let mut import_insert = TextEdit::builder();
        algo::diff(&old_ast, &rewriter.rewrite(&old_ast)).into_text_edit(&mut import_insert);

        Some(import_insert.finish())
    }
}

/// A helper to make `CompletionItem`s.
#[must_use]
#[derive(Clone)]
pub(crate) struct Builder {
    source_range: TextRange,
    completion_kind: CompletionKind,
    import_to_add: Option<ImportEdit>,
    label: String,
    insert_text: Option<String>,
    insert_text_format: InsertTextFormat,
    detail: Option<String>,
    documentation: Option<Documentation>,
    lookup: Option<String>,
    kind: Option<CompletionItemKind>,
    text_edit: Option<TextEdit>,
    deprecated: Option<bool>,
    trigger_call_info: Option<bool>,
    score: Option<CompletionScore>,
    ref_match: Option<(Mutability, CompletionScore)>,
}

impl Builder {
    pub(crate) fn build(self) -> CompletionItem {
        let _p = profile::span("item::Builder::build");

        let mut label = self.label;
        let mut lookup = self.lookup;
        let mut insert_text = self.insert_text;

        if let Some(original_path) = self
            .import_to_add
            .as_ref()
            .and_then(|import_edit| import_edit.import.original_path.as_ref())
        {
            lookup = lookup.or_else(|| Some(label.clone()));
            insert_text = insert_text.or_else(|| Some(label.clone()));

            let original_path_label = original_path.to_string();
            if original_path_label.ends_with(&label) {
                label = original_path_label;
            } else {
                format_to!(label, " ({})", original_path)
            }
        }

        let text_edit = match self.text_edit {
            Some(it) => it,
            None => {
                TextEdit::replace(self.source_range, insert_text.unwrap_or_else(|| label.clone()))
            }
        };

        CompletionItem {
            source_range: self.source_range,
            label,
            insert_text_format: self.insert_text_format,
            text_edit,
            detail: self.detail,
            documentation: self.documentation,
            lookup,
            kind: self.kind,
            completion_kind: self.completion_kind,
            deprecated: self.deprecated.unwrap_or(false),
            trigger_call_info: self.trigger_call_info.unwrap_or(false),
            score: self.score,
            ref_match: self.ref_match,
            import_to_add: self.import_to_add,
        }
    }
    pub(crate) fn lookup_by(mut self, lookup: impl Into<String>) -> Builder {
        self.lookup = Some(lookup.into());
        self
    }
    pub(crate) fn label(mut self, label: impl Into<String>) -> Builder {
        self.label = label.into();
        self
    }
    pub(crate) fn insert_text(mut self, insert_text: impl Into<String>) -> Builder {
        self.insert_text = Some(insert_text.into());
        self
    }
    pub(crate) fn insert_snippet(
        mut self,
        _cap: SnippetCap,
        snippet: impl Into<String>,
    ) -> Builder {
        self.insert_text_format = InsertTextFormat::Snippet;
        self.insert_text(snippet)
    }
    pub(crate) fn kind(mut self, kind: impl Into<CompletionItemKind>) -> Builder {
        self.kind = Some(kind.into());
        self
    }
    pub(crate) fn text_edit(mut self, edit: TextEdit) -> Builder {
        self.text_edit = Some(edit);
        self
    }
    pub(crate) fn snippet_edit(mut self, _cap: SnippetCap, edit: TextEdit) -> Builder {
        self.insert_text_format = InsertTextFormat::Snippet;
        self.text_edit(edit)
    }
    pub(crate) fn detail(self, detail: impl Into<String>) -> Builder {
        self.set_detail(Some(detail))
    }
    pub(crate) fn set_detail(mut self, detail: Option<impl Into<String>>) -> Builder {
        self.detail = detail.map(Into::into);
        if let Some(detail) = &self.detail {
            if never!(detail.contains('\n'), "multiline detail:\n{}", detail) {
                self.detail = Some(detail.splitn(2, '\n').next().unwrap().to_string());
            }
        }
        self
    }
    #[allow(unused)]
    pub(crate) fn documentation(self, docs: Documentation) -> Builder {
        self.set_documentation(Some(docs))
    }
    pub(crate) fn set_documentation(mut self, docs: Option<Documentation>) -> Builder {
        self.documentation = docs.map(Into::into);
        self
    }
    pub(crate) fn set_deprecated(mut self, deprecated: bool) -> Builder {
        self.deprecated = Some(deprecated);
        self
    }
    pub(crate) fn set_score(mut self, score: CompletionScore) -> Builder {
        self.score = Some(score);
        self
    }
    pub(crate) fn trigger_call_info(mut self) -> Builder {
        self.trigger_call_info = Some(true);
        self
    }
    pub(crate) fn add_import(mut self, import_to_add: Option<ImportEdit>) -> Builder {
        self.import_to_add = import_to_add;
        self
    }
    pub(crate) fn set_ref_match(
        mut self,
        ref_match: Option<(Mutability, CompletionScore)>,
    ) -> Builder {
        self.ref_match = ref_match;
        self
    }
}

// impl<'a> Into<CompletionItem> for Builder {
//     fn into(self) -> CompletionItem {
//         self.build()
//     }
// }
<commit_msg>Cleanup<commit_after>//! See `CompletionItem` structure.

use std::fmt;

use hir::{Documentation, Mutability};
use ide_db::{
    helpers::{
        import_assets::LocatedImport,
        insert_use::{self, ImportScope, InsertUseConfig},
        mod_path_to_ast, SnippetCap,
    },
    SymbolKind,
};
use stdx::{format_to, impl_from, never};
use syntax::{algo, TextRange};
use text_edit::TextEdit;

/// `CompletionItem` describes a single completion variant in the editor pop-up.
/// It is basically a POD with various properties. To construct a
/// `CompletionItem`, use `new` method and the `Builder` struct.
#[derive(Clone)]
pub struct CompletionItem {
    /// Used only internally in tests, to check only specific kind of
    /// completion (postfix, keyword, reference, etc).
    #[allow(unused)]
    pub(crate) completion_kind: CompletionKind,
    /// Label in the completion pop up which identifies completion.
    label: String,
    /// Range of identifier that is being completed.
    ///
    /// It should be used primarily for UI, but we also use this to convert
    /// genetic TextEdit into LSP's completion edit (see conv.rs).
    ///
    /// `source_range` must contain the completion offset. `insert_text` should
    /// start with what `source_range` points to, or VSCode will filter out the
    /// completion silently.
    source_range: TextRange,
    /// What happens when user selects this item.
    ///
    /// Typically, replaces `source_range` with new identifier.
    text_edit: TextEdit,

    insert_text_format: InsertTextFormat,

    /// What item (struct, function, etc) are we completing.
    kind: Option<CompletionItemKind>,

    /// Lookup is used to check if completion item indeed can complete current
    /// ident.
    ///
    /// That is, in `foo.bar$0` lookup of `abracadabra` will be accepted (it
    /// contains `bar` sub sequence), and `quux` will rejected.
    lookup: Option<String>,

    /// Additional info to show in the UI pop up.
    detail: Option<String>,
    documentation: Option<Documentation>,

    /// Whether this item is marked as deprecated
    deprecated: bool,

    /// If completing a function call, ask the editor to show parameter popup
    /// after completion.
    trigger_call_info: bool,

    /// Score is useful to pre select or display in better order completion items
    score: Option<CompletionScore>,

    /// Indicates that a reference or mutable reference to this variable is a
    /// possible match.
    ref_match: Option<(Mutability, CompletionScore)>,

    /// The import data to add to completion's edits.
    import_to_add: Option<ImportEdit>,
}

// We use custom debug for CompletionItem to make snapshot tests more readable.
impl fmt::Debug for CompletionItem {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut s = f.debug_struct("CompletionItem");
        s.field("label", &self.label()).field("source_range", &self.source_range());
        if self.text_edit().len() == 1 {
            let atom = &self.text_edit().iter().next().unwrap();
            s.field("delete", &atom.delete);
            s.field("insert", &atom.insert);
        } else {
            s.field("text_edit", &self.text_edit);
        }
        if let Some(kind) = self.kind().as_ref() {
            s.field("kind", kind);
        }
        if self.lookup() != self.label() {
            s.field("lookup", &self.lookup());
        }
        if let Some(detail) = self.detail() {
            s.field("detail", &detail);
        }
        if let Some(documentation) = self.documentation() {
            s.field("documentation", &documentation);
        }
        if self.deprecated {
            s.field("deprecated", &true);
        }
        if let Some(score) = &self.score {
            s.field("score", score);
        }
        if self.trigger_call_info {
            s.field("trigger_call_info", &true);
        }
        s.finish()
    }
}

#[derive(Debug, Clone, Copy, Ord, PartialOrd, Eq, PartialEq)]
pub enum CompletionScore {
    /// If only type match
    TypeMatch,
    /// If type and name match
    TypeAndNameMatch,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CompletionItemKind {
    SymbolKind(SymbolKind),
    Attribute,
    Binding,
    BuiltinType,
    Keyword,
    Method,
    Snippet,
    UnresolvedReference,
}

impl_from!(SymbolKind for CompletionItemKind);

impl CompletionItemKind {
    #[cfg(test)]
    pub(crate) fn tag(&self) -> &'static str {
        match self {
            CompletionItemKind::SymbolKind(kind) => match kind {
                SymbolKind::Const => "ct",
                SymbolKind::ConstParam => "cp",
                SymbolKind::Enum => "en",
                SymbolKind::Field => "fd",
                SymbolKind::Function => "fn",
                SymbolKind::Impl => "im",
                SymbolKind::Label => "lb",
                SymbolKind::LifetimeParam => "lt",
                SymbolKind::Local => "lc",
                SymbolKind::Macro => "ma",
                SymbolKind::Module => "md",
                SymbolKind::SelfParam => "sp",
                SymbolKind::Static => "sc",
                SymbolKind::Struct => "st",
                SymbolKind::Trait => "tt",
                SymbolKind::TypeAlias => "ta",
                SymbolKind::TypeParam => "tp",
                SymbolKind::Union => "un",
                SymbolKind::ValueParam => "vp",
                SymbolKind::Variant => "ev",
            },
            CompletionItemKind::Attribute => "at",
            CompletionItemKind::Binding => "bn",
            CompletionItemKind::BuiltinType => "bt",
            CompletionItemKind::Keyword => "kw",
            CompletionItemKind::Method => "me",
            CompletionItemKind::Snippet => "sn",
            CompletionItemKind::UnresolvedReference => "??",
        }
    }
}

#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub(crate) enum CompletionKind {
    /// Parser-based keyword completion.
    Keyword,
    /// Your usual "complete all valid identifiers".
    Reference,
    /// "Secret sauce" completions.
    Magic,
    Snippet,
    Postfix,
    BuiltinType,
    Attribute,
}

#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum InsertTextFormat {
    PlainText,
    Snippet,
}

impl CompletionItem {
    pub(crate) fn new(
        completion_kind: CompletionKind,
        source_range: TextRange,
        label: impl Into<String>,
    ) -> Builder {
        let label = label.into();
        Builder {
            source_range,
            completion_kind,
            label,
            insert_text: None,
            insert_text_format: InsertTextFormat::PlainText,
            detail: None,
            documentation: None,
            lookup: None,
            kind: None,
            text_edit: None,
            deprecated: None,
            trigger_call_info: None,
            score: None,
            ref_match: None,
            import_to_add: None,
        }
    }

    /// What user sees in pop-up in the UI.
    pub fn label(&self) -> &str {
        &self.label
    }
    pub fn source_range(&self) -> TextRange {
        self.source_range
    }

    pub fn insert_text_format(&self) -> InsertTextFormat {
        self.insert_text_format
    }

    pub fn text_edit(&self) -> &TextEdit {
        &self.text_edit
    }

    /// Short one-line additional information, like a type
    pub fn detail(&self) -> Option<&str> {
        self.detail.as_deref()
    }
    /// A doc-comment
    pub fn documentation(&self) -> Option<Documentation> {
        self.documentation.clone()
    }
    /// What string is used for filtering.
    pub fn lookup(&self) -> &str {
        self.lookup.as_deref().unwrap_or(&self.label)
    }

    pub fn kind(&self) -> Option<CompletionItemKind> {
        self.kind
    }

    pub fn deprecated(&self) -> bool {
        self.deprecated
    }

    pub fn score(&self) -> Option<CompletionScore> {
        self.score
    }

    pub fn trigger_call_info(&self) -> bool {
        self.trigger_call_info
    }

    pub fn ref_match(&self) -> Option<(Mutability, CompletionScore)> {
        self.ref_match
    }

    pub fn import_to_add(&self) -> Option<&ImportEdit> {
        self.import_to_add.as_ref()
    }
}

/// An extra import to add after the completion is applied.
#[derive(Debug, Clone)]
pub struct ImportEdit {
    pub import: LocatedImport,
    pub scope: ImportScope,
}

impl ImportEdit {
    /// Attempts to insert the import to the given scope, producing a text edit.
    /// May return no edit in edge cases, such as scope already containing the import.
    pub fn to_text_edit(&self, cfg: InsertUseConfig) -> Option<TextEdit> {
        let _p = profile::span("ImportEdit::to_text_edit");

        let rewriter = insert_use::insert_use(
            &self.scope,
            mod_path_to_ast(&self.import.import_path),
            cfg,
        );
        let old_ast = rewriter.rewrite_root()?;
        let mut import_insert = TextEdit::builder();
        algo::diff(&old_ast, &rewriter.rewrite(&old_ast)).into_text_edit(&mut import_insert);

        Some(import_insert.finish())
    }
}

/// A helper to make `CompletionItem`s.
#[must_use]
#[derive(Clone)]
pub(crate) struct Builder {
    source_range: TextRange,
    completion_kind: CompletionKind,
    import_to_add: Option<ImportEdit>,
    label: String,
    insert_text: Option<String>,
    insert_text_format: InsertTextFormat,
    detail: Option<String>,
    documentation: Option<Documentation>,
    lookup: Option<String>,
    kind: Option<CompletionItemKind>,
    text_edit: Option<TextEdit>,
    deprecated: Option<bool>,
    trigger_call_info: Option<bool>,
    score: Option<CompletionScore>,
    ref_match: Option<(Mutability, CompletionScore)>,
}

impl Builder {
    pub(crate) fn build(self) -> CompletionItem {
        let _p = profile::span("item::Builder::build");

        let mut label = self.label;
        let mut lookup = self.lookup;
        let mut insert_text = self.insert_text;

        if let Some(original_path) = self
            .import_to_add
            .as_ref()
            .and_then(|import_edit| import_edit.import.original_path.as_ref())
        {
            lookup = lookup.or_else(|| Some(label.clone()));
            insert_text = insert_text.or_else(|| Some(label.clone()));

            let original_path_label = original_path.to_string();
            if original_path_label.ends_with(&label) {
                label = original_path_label;
            } else {
                format_to!(label, " ({})", original_path)
            }
        }

        let text_edit = match self.text_edit {
            Some(it) => it,
            None => {
                TextEdit::replace(self.source_range, insert_text.unwrap_or_else(|| label.clone()))
            }
        };

        CompletionItem {
            source_range: self.source_range,
            label,
            insert_text_format: self.insert_text_format,
            text_edit,
            detail: self.detail,
            documentation: self.documentation,
            lookup,
            kind: self.kind,
            completion_kind: self.completion_kind,
            deprecated: self.deprecated.unwrap_or(false),
            trigger_call_info: self.trigger_call_info.unwrap_or(false),
            score: self.score,
            ref_match: self.ref_match,
            import_to_add: self.import_to_add,
        }
    }
    pub(crate) fn lookup_by(mut self, lookup: impl Into<String>) -> Builder {
        self.lookup = Some(lookup.into());
        self
    }
    pub(crate) fn label(mut self, label: impl Into<String>) -> Builder {
        self.label = label.into();
        self
    }
    pub(crate) fn insert_text(mut self, insert_text: impl Into<String>) -> Builder {
        self.insert_text = Some(insert_text.into());
        self
    }
    pub(crate) fn insert_snippet(
        mut self,
        _cap: SnippetCap,
        snippet: impl Into<String>,
    ) -> Builder {
        self.insert_text_format = InsertTextFormat::Snippet;
        self.insert_text(snippet)
    }
    pub(crate) fn kind(mut self, kind: impl Into<CompletionItemKind>) -> Builder {
        self.kind = Some(kind.into());
        self
    }
    pub(crate) fn text_edit(mut self, edit: TextEdit) -> Builder {
        self.text_edit = Some(edit);
        self
    }
    pub(crate) fn snippet_edit(mut self, _cap: SnippetCap, edit: TextEdit) -> Builder {
        self.insert_text_format = InsertTextFormat::Snippet;
        self.text_edit(edit)
    }
    pub(crate) fn detail(self, detail: impl Into<String>) -> Builder {
        self.set_detail(Some(detail))
    }
    pub(crate) fn set_detail(mut self, detail: Option<impl Into<String>>) -> Builder {
        self.detail = detail.map(Into::into);
        if let Some(detail) = &self.detail {
            if never!(detail.contains('\n'), "multiline detail:\n{}", detail) {
                self.detail = Some(detail.splitn(2, '\n').next().unwrap().to_string());
            }
        }
        self
    }
    #[allow(unused)]
    pub(crate) fn documentation(self, docs: Documentation) -> Builder {
        self.set_documentation(Some(docs))
    }
    pub(crate) fn set_documentation(mut self, docs: Option<Documentation>) -> Builder {
        self.documentation = docs.map(Into::into);
        self
    }
    pub(crate) fn set_deprecated(mut self, deprecated: bool) -> Builder {
        self.deprecated = Some(deprecated);
        self
    }
    pub(crate) fn set_score(mut self, score: CompletionScore) -> Builder {
        self.score = Some(score);
        self
    }
    pub(crate) fn trigger_call_info(mut self) -> Builder {
        self.trigger_call_info = Some(true);
        self
    }
    pub(crate) fn add_import(mut self, import_to_add: Option<ImportEdit>) -> Builder {
        self.import_to_add = import_to_add;
        self
    }
    pub(crate) fn set_ref_match(
        mut self,
        ref_match: Option<(Mutability, CompletionScore)>,
    ) -> Builder {
        self.ref_match = ref_match;
        self
    }
}
<|endoftext|>


<commit_before>use super::behaviors::MouseBehavior;
use crate::prelude::*;
use crate::shell::{Key, KeyEvent};
use core::f64::MAX;
use rust_decimal::prelude::*;

pub static ID_INPUT: &'static str = "numeric_box_input";
pub static ELEMENT_INPUT: &'static str = "numeric_box_input";
pub static ELEMENT_BTN: &'static str = "numeric_box_button";
// one mouse up scroll is delta.y = 12.0
static ONE_SCROLL: f64 = 12.0;

pub enum InputAction {
    Inc,
    Dec,
    ChangeByKey(KeyEvent),
    ChangeByMouseScroll(Point),
    Focus,
}

#[derive(Default, AsAny)]
pub struct NumericBoxState {
    pub action: Option<InputAction>,
    pub input: Entity,
    pub min: Decimal,
    pub max: Decimal,
    pub step: Decimal,
    pub current_value: Decimal,
}

impl NumericBoxState {
    fn action(&mut self, action: InputAction) {
        self.action = Some(action);
    }

    fn change_val(&mut self, new_value: Decimal, ctx: &mut Context) {
        if new_value >= self.min && new_value <= self.max {
            self.current_value = new_value;
            ctx.get_widget(self.input)
                .set::<String16>("text", String16::from(self.current_value.to_string()));

            ctx.push_event_strategy_by_entity(
                ChangedEvent(ctx.entity),
                ctx.entity,
                EventStrategy::Direct,
            );
        }
    }

    fn request_focus(&self, ctx: &mut Context) {
        if !ctx.widget().get::<bool>("focused") {
            ctx.widget().set::<bool>("focused", true);
            ctx.push_event_by_window(FocusEvent::RequestFocus(ctx.entity));
        }
    }
}

fn default_or(key: &str, default_value: f64, ctx: &mut Context) -> Decimal {
    let property = ctx.widget().clone_or_default(key);

    match Decimal::from_f64(property) {
        Some(val) => val,
        None => Decimal::from_f64(default_value).unwrap(),
    }
}

impl State for NumericBoxState {
    fn init(&mut self, _: &mut Registry, ctx: &mut Context) {
        self.input = ctx.entity_of_child(ID_INPUT).expect(
            "NumericBoxState
        .init(): the child input could not be found!",
        );
        self.min = default_or("min", 0.0, ctx);
        self.max = default_or("max", MAX, ctx);
        self.step = default_or("step", 1.0, ctx);
        self.current_value = default_or("val", 0.0, ctx);

        let init_value = String16::from(self.current_value.to_string());
        ctx.get_widget(self.input)
            .set::<String16>("text", init_value);
    }

    // TODO: let the user type the value, or select it for cut, copy, paste operations
    fn update(&mut self, _: &mut Registry, ctx: &mut Context) {
        if let Some(action) = &self.action {
            match action {
                InputAction::Inc => {
                    self.change_val(self.current_value + self.step, ctx);
                }
                InputAction::Dec => {
                    self.change_val(self.current_value - self.step, ctx);
                }
                InputAction::ChangeByKey(key_event) => match key_event.key {
                    Key::Up | Key::NumpadAdd => {
                        self.change_val(self.current_value + self.step, ctx);
                    }
                    Key::Down | Key::NumpadSubtract => {
                        self.change_val(self.current_value - self.step, ctx);
                    }
                    Key::Enter => {
                        if *ctx.widget().get::<bool>("lost_focus_on_activation") {
                            ctx.push_event_by_window(FocusEvent::RemoveFocus(ctx.entity));
                        }

                        ctx.push_event_strategy_by_entity(
                            ActivateEvent(ctx.entity),
                            ctx.entity,
                            EventStrategy::Direct,
                        )
                    }
                    _ => {}
                },
                InputAction::ChangeByMouseScroll(delta) => {
                    match Decimal::from_f64(delta.y / ONE_SCROLL) {
                        Some(scroll_count) => {
                            self.change_val(self.current_value + (self.step * scroll_count), ctx);
                        }
                        None => {}
                    }
                }
                InputAction::Focus => {
                    self.request_focus(ctx);
                }
            }
            self.action = None;
        }
    }
}

widget!(
    /// `NumericBox` is used to let the user increase or decrease
    /// the value of the input by a given, fixed value called `step` until it reaches the upper or
    /// lower bounds.
    /// The widget can be controlled by clicking on the two control buttons, or the keybaord's
    /// Up and Down, Numpad+ and Numpad- keys, or the mouse scroll.
    /// Note: after the widget is initialized, changing the min, max or step properties has no effect.
    ///
    /// # Examples:
    /// Create a NumericBox with default values:
    /// ```rust
    /// NumericBox::new().build(ctx)
    /// ```
    ///
    /// Create a NumericBox with custom values:
    /// ```rust
    /// NumericBox::new().min(10.0).max(100.0).val(50.0).step(5.0).build(ctx)
    /// ```
    NumericBox<NumericBoxState>: ActivateHandler, ChangedHandler, KeyDownHandler {
        /// Sets or shares the background color property
        background: Brush,

        /// Sets or shares the border color property
        border_brush: Brush,

        /// Sets or shares the border width property
        border_width: Thickness,

        /// Sets or shares the border radius property
        border_radius: f64,

        /// Sets or shares the focused property
        focused: bool,

        /// Sets or shares the foreground color property
        foreground: Brush,

        /// Sets or shares the value that describes if the NumericBox should lost focus on activation (when enter pressed).
        lost_focus_on_activation: bool,

        /// Sets or shares the minimum allowed value property
        min: f64,

        /// Sets or shares the maximum allowed value property
        max: f64,

        /// Sets or shares the stepping value property
        step: f64,

        /// Sets or shares the current value property
        val: f64
    }
);

impl Template for NumericBox {
    fn template(self, id: Entity, ctx: &mut BuildContext) -> Self {
        self.name("NumericBox")
            .background("transparent")
            .foreground(colors::LINK_WATER_COLOR)
            .border_brush("#647b91")
            .border_width(1.0)
            .border_radius(3.0)
            .element("numeric_box")
            .focused(false)
            .height(32.0)
            .lost_focus_on_activation(true)
            .margin(4.0)
            .min(0.0)
            .max(200.0)
            .step(1.0)
            .val(0.0)
            .width(128.0)
            .child(
                MouseBehavior::new()
                    .on_mouse_down(move |states, _| {
                        states
                            .get_mut::<NumericBoxState>(id)
                            .action(InputAction::Focus);
                        true
                    })
                    .on_scroll(move |states, delta| {
                        states
                            .get_mut::<NumericBoxState>(id)
                            .action(InputAction::ChangeByMouseScroll(delta));
                        true
                    })
                    .build(ctx),
            )
            .child(
                Grid::new()
                    .columns(Columns::new().add("*").add(32.))
                    .rows(Rows::new().add(16.0).add(16.0))
                    .child(
                        TextBox::new()
                            .h_align("stretch")
                            .attach(Grid::column(0))
                            .attach(Grid::row_span(2))
                            .attach(Grid::row(0))
                            .border_brush(id)
                            .border_radius(id)
                            .border_width(id)
                            .element(ELEMENT_INPUT)
                            .enabled(false)
                            .id(ID_INPUT)
                            .max_width(96.)
                            .text("0")
                            .build(ctx),
                    )
                    .child(
                        Button::new()
                            .attach(Grid::column(1))
                            .attach(Grid::row(0))
                            .border_brush("transparent")
                            .border_radius(0.0)
                            .border_width(0.0)
                            .min_width(30.0)
                            .height(30.0)
                            .class("single_content")
                            .element(ELEMENT_BTN)
                            .text("+")
                            .margin(1)
                            .on_click(move |states, _| {
                                states
                                    .get_mut::<NumericBoxState>(id)
                                    .action(InputAction::Inc);
                                true
                            })
                            .build(ctx),
                    )
                    .child(
                        Button::new()
                            .attach(Grid::column(1))
                            .attach(Grid::row(1))
                            .border_brush("transparent")
                            .border_radius(0.0)
                            .border_width(0.0)
                            .class("single_content")
                            .element(ELEMENT_BTN)
                            .min_width(30.0)
                            .height(30.0)
                            .padding(0.0)
                            .margin(1)
                            .text("-")
                            .on_click(move |states, _| {
                                states
                                    .get_mut::<NumericBoxState>(id)
                                    .action(InputAction::Dec);
                                true
                            })
                            .build(ctx),
                    )
                    .build(ctx),
            )
            .on_key_down(move |states, event| -> bool {
                states
                    .get_mut::<NumericBoxState>(id)
                    .action(InputAction::ChangeByKey(event));
                false
            })
    }

    fn render_object(&self) -> Box<dyn RenderObject> {
        Box::new(RectangleRenderObject)
    }
}
<commit_msg>Clamp values to allowed ranges<commit_after>use super::behaviors::MouseBehavior;
use crate::prelude::*;
use crate::shell::{Key, KeyEvent};
use core::f64::MAX;
use rust_decimal::prelude::*;

pub static ID_INPUT: &'static str = "numeric_box_input";
pub static ELEMENT_INPUT: &'static str = "numeric_box_input";
pub static ELEMENT_BTN: &'static str = "numeric_box_button";
// one mouse up scroll is delta.y = 12.0
static ONE_SCROLL: f64 = 12.0;

pub enum InputAction {
    Inc,
    Dec,
    ChangeByKey(KeyEvent),
    ChangeByMouseScroll(Point),
    Focus,
}

#[derive(Default, AsAny)]
pub struct NumericBoxState {
    pub action: Option<InputAction>,
    pub input: Entity,
    pub min: Decimal,
    pub max: Decimal,
    pub step: Decimal,
    pub current_value: Decimal,
}

impl NumericBoxState {
    fn action(&mut self, action: InputAction) {
        self.action = Some(action);
    }

    fn change_val(&mut self, new_value: Decimal, ctx: &mut Context) {
        self.current_value = self.max(self.min(new_value));
        ctx.get_widget(self.input)
            .set::<String16>("text", String16::from(self.current_value.to_string()));

        ctx.push_event_strategy_by_entity(
            ChangedEvent(ctx.entity),
            ctx.entity,
            EventStrategy::Direct,
        );
    }

    fn min(&self, d: Decimal) -> Decimal {
        if d < self.min {
            return self.min;
        } else {
            return d;
        }
    }

    fn max(&self, d: Decimal) -> Decimal {
       if d > self.max {
           return self.max;
       } else {
           return d;
       }
    }

    fn request_focus(&self, ctx: &mut Context) {
        if !ctx.widget().get::<bool>("focused") {
            ctx.widget().set::<bool>("focused", true);
            ctx.push_event_by_window(FocusEvent::RequestFocus(ctx.entity));
        }
    }
}

fn default_or(key: &str, default_value: f64, ctx: &mut Context) -> Decimal {
    let property = ctx.widget().clone_or_default(key);

    match Decimal::from_f64(property) {
        Some(val) => val,
        None => Decimal::from_f64(default_value).unwrap(),
    }
}

impl State for NumericBoxState {
    fn init(&mut self, _: &mut Registry, ctx: &mut Context) {
        self.input = ctx.entity_of_child(ID_INPUT).expect(
            "NumericBoxState
        .init(): the child input could not be found!",
        );
        self.min = default_or("min", 0.0, ctx);
        self.max = default_or("max", MAX, ctx);
        self.step = default_or("step", 1.0, ctx);
        self.current_value = default_or("val", 0.0, ctx);

        let init_value = String16::from(self.current_value.to_string());
        ctx.get_widget(self.input)
            .set::<String16>("text", init_value);
    }

    // TODO: let the user type the value, or select it for cut, copy, paste operations
    fn update(&mut self, _: &mut Registry, ctx: &mut Context) {
        if let Some(action) = &self.action {
            match action {
                InputAction::Inc => {
                    self.change_val(self.current_value + self.step, ctx);
                }
                InputAction::Dec => {
                    self.change_val(self.current_value - self.step, ctx);
                }
                InputAction::ChangeByKey(key_event) => match key_event.key {
                    Key::Up | Key::NumpadAdd => {
                        self.change_val(self.current_value + self.step, ctx);
                    }
                    Key::Down | Key::NumpadSubtract => {
                        self.change_val(self.current_value - self.step, ctx);
                    }
                    Key::Enter => {
                        if *ctx.widget().get::<bool>("lost_focus_on_activation") {
                            ctx.push_event_by_window(FocusEvent::RemoveFocus(ctx.entity));
                        }

                        ctx.push_event_strategy_by_entity(
                            ActivateEvent(ctx.entity),
                            ctx.entity,
                            EventStrategy::Direct,
                        )
                    }
                    _ => {}
                },
                InputAction::ChangeByMouseScroll(delta) => {
                    match Decimal::from_f64(delta.y / ONE_SCROLL) {
                        Some(scroll_count) => {
                            self.change_val(self.current_value + (self.step * scroll_count), ctx);
                        }
                        None => {}
                    }
                }
                InputAction::Focus => {
                    self.request_focus(ctx);
                }
            }
            self.action = None;
        }
    }
}

widget!(
    /// `NumericBox` is used to let the user increase or decrease
    /// the value of the input by a given, fixed value called `step` until it reaches the upper or
    /// lower bounds.
    /// The widget can be controlled by clicking on the two control buttons, or the keybaord's
    /// Up and Down, Numpad+ and Numpad- keys, or the mouse scroll.
    /// Note: after the widget is initialized, changing the min, max or step properties has no effect.
    ///
    /// # Examples:
    /// Create a NumericBox with default values:
    /// ```rust
    /// NumericBox::new().build(ctx)
    /// ```
    ///
    /// Create a NumericBox with custom values:
    /// ```rust
    /// NumericBox::new().min(10.0).max(100.0).val(50.0).step(5.0).build(ctx)
    /// ```
    NumericBox<NumericBoxState>: ActivateHandler, ChangedHandler, KeyDownHandler {
        /// Sets or shares the background color property
        background: Brush,

        /// Sets or shares the border color property
        border_brush: Brush,

        /// Sets or shares the border width property
        border_width: Thickness,

        /// Sets or shares the border radius property
        border_radius: f64,

        /// Sets or shares the focused property
        focused: bool,

        /// Sets or shares the foreground color property
        foreground: Brush,

        /// Sets or shares the value that describes if the NumericBox should lost focus on activation (when enter pressed).
        lost_focus_on_activation: bool,

        /// Sets or shares the minimum allowed value property
        min: f64,

        /// Sets or shares the maximum allowed value property
        max: f64,

        /// Sets or shares the stepping value property
        step: f64,

        /// Sets or shares the current value property
        val: f64
    }
);

impl Template for NumericBox {
    fn template(self, id: Entity, ctx: &mut BuildContext) -> Self {
        self.name("NumericBox")
            .background("transparent")
            .foreground(colors::LINK_WATER_COLOR)
            .border_brush("#647b91")
            .border_width(1.0)
            .border_radius(3.0)
            .element("numeric_box")
            .focused(false)
            .height(32.0)
            .lost_focus_on_activation(true)
            .margin(4.0)
            .min(0.0)
            .max(200.0)
            .step(1.0)
            .val(0.0)
            .width(128.0)
            .child(
                MouseBehavior::new()
                    .on_mouse_down(move |states, _| {
                        states
                            .get_mut::<NumericBoxState>(id)
                            .action(InputAction::Focus);
                        true
                    })
                    .on_scroll(move |states, delta| {
                        states
                            .get_mut::<NumericBoxState>(id)
                            .action(InputAction::ChangeByMouseScroll(delta));
                        true
                    })
                    .build(ctx),
            )
            .child(
                Grid::new()
                    .columns(Columns::new().add("*").add(32.))
                    .rows(Rows::new().add(16.0).add(16.0))
                    .child(
                        TextBox::new()
                            .h_align("stretch")
                            .attach(Grid::column(0))
                            .attach(Grid::row_span(2))
                            .attach(Grid::row(0))
                            .border_brush(id)
                            .border_radius(id)
                            .border_width(id)
                            .element(ELEMENT_INPUT)
                            .enabled(false)
                            .id(ID_INPUT)
                            .max_width(96.)
                            .text("0")
                            .build(ctx),
                    )
                    .child(
                        Button::new()
                            .attach(Grid::column(1))
                            .attach(Grid::row(0))
                            .border_brush("transparent")
                            .border_radius(0.0)
                            .border_width(0.0)
                            .min_width(30.0)
                            .height(30.0)
                            .class("single_content")
                            .element(ELEMENT_BTN)
                            .text("+")
                            .margin(1)
                            .on_click(move |states, _| {
                                states
                                    .get_mut::<NumericBoxState>(id)
                                    .action(InputAction::Inc);
                                true
                            })
                            .build(ctx),
                    )
                    .child(
                        Button::new()
                            .attach(Grid::column(1))
                            .attach(Grid::row(1))
                            .border_brush("transparent")
                            .border_radius(0.0)
                            .border_width(0.0)
                            .class("single_content")
                            .element(ELEMENT_BTN)
                            .min_width(30.0)
                            .height(30.0)
                            .padding(0.0)
                            .margin(1)
                            .text("-")
                            .on_click(move |states, _| {
                                states
                                    .get_mut::<NumericBoxState>(id)
                                    .action(InputAction::Dec);
                                true
                            })
                            .build(ctx),
                    )
                    .build(ctx),
            )
            .on_key_down(move |states, event| -> bool {
                states
                    .get_mut::<NumericBoxState>(id)
                    .action(InputAction::ChangeByKey(event));
                false
            })
    }

    fn render_object(&self) -> Box<dyn RenderObject> {
        Box::new(RectangleRenderObject)
    }
}
<|endoftext|>


<commit_before>//! Data structures and implementations.

pub use self::dmat::{DMat, DMat1, DMat2, DMat3, DMat4, DMat5, DMat6};
pub use self::dvec::{DVec, DVec1, DVec2, DVec3, DVec4, DVec5, DVec6};
pub use self::vec::{Vec1, Vec2, Vec3, Vec4, Vec5, Vec6};
pub use self::vecn::VecN;
pub use self::pnt::{Pnt1, Pnt2, Pnt3, Pnt4, Pnt5, Pnt6};
pub use self::mat::{Identity, Mat1, Mat2, Mat3, Mat4, Mat5, Mat6};
pub use self::rot::{Rot2, Rot3};
pub use self::iso::{Iso2, Iso3};
pub use self::sim::{Sim2, Sim3};
pub use self::persp::{Persp3, PerspMat3};
pub use self::ortho::{Ortho3, OrthoMat3};
pub use self::quat::{Quat, UnitQuat};

mod dmat_macros;
mod dmat;
mod vecn_macros;
mod vecn;
mod dvec_macros;
mod dvec;
mod vec_macros;
mod vec;
mod pnt_macros;
mod pnt;
mod quat;
mod mat_macros;
mod mat;
mod rot_macros;
mod rot;
mod iso_macros;
mod iso;
mod sim_macros;
mod sim;
mod persp;
mod ortho;

// specialization for some 1d, 2d and 3d operations
#[doc(hidden)]
mod spec {
    mod identity;
    mod mat;
    mod vec;
    mod primitives;
    // mod complex;
}
<commit_msg>Minor comment fix.<commit_after>//! Data structures and implementations.

pub use self::dmat::{DMat, DMat1, DMat2, DMat3, DMat4, DMat5, DMat6};
pub use self::dvec::{DVec, DVec1, DVec2, DVec3, DVec4, DVec5, DVec6};
pub use self::vec::{Vec1, Vec2, Vec3, Vec4, Vec5, Vec6};
pub use self::vecn::VecN;
pub use self::pnt::{Pnt1, Pnt2, Pnt3, Pnt4, Pnt5, Pnt6};
pub use self::mat::{Identity, Mat1, Mat2, Mat3, Mat4, Mat5, Mat6};
pub use self::rot::{Rot2, Rot3};
pub use self::iso::{Iso2, Iso3};
pub use self::sim::{Sim2, Sim3};
pub use self::persp::{Persp3, PerspMat3};
pub use self::ortho::{Ortho3, OrthoMat3};
pub use self::quat::{Quat, UnitQuat};

mod dmat_macros;
mod dmat;
mod vecn_macros;
mod vecn;
mod dvec_macros;
mod dvec;
mod vec_macros;
mod vec;
mod pnt_macros;
mod pnt;
mod quat;
mod mat_macros;
mod mat;
mod rot_macros;
mod rot;
mod iso_macros;
mod iso;
mod sim_macros;
mod sim;
mod persp;
mod ortho;

// Specialization for some 1d, 2d and 3d operations.
#[doc(hidden)]
mod spec {
    mod identity;
    mod mat;
    mod vec;
    mod primitives;
    // mod complex;
}
<|endoftext|>


<commit_before>// Copyright 2013 Tommy M. McGuire
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#[ link(name = "fashhashmap", vers="1.0") ];
#[ crate_type = "lib" ];

use std::rt::io::Writer;
use std::to_bytes::IterBytes;
use std::vec;
use std::uint;
use std::util;

// Simple Writer/IterBytes based implementation of the DJB hash
// (See http://cr.yp.to/cdb/cdb.txt and http://www.cse.yorku.ca/~oz/hash.html)
struct DJBState {
    hash : u64
}

impl DJBState {
    fn new() -> DJBState { DJBState { hash : 5381u64 } }

    #[inline]
    fn djbhash<T:IterBytes>(t : &T) -> u64 {
        let mut state = DJBState::new();
        t.iter_bytes(true, |b| { state.write(b); true });
        state.flush();
        return state.hash();
    }

    fn hash(&self) -> u64 { self.hash }
}

impl Writer for DJBState {
    #[inline]
    fn write(&mut self, buf : &[u8]) {
        let len = buf.len();
        let mut i = 0;
        while i < len { self.hash = (33u64 * self.hash) ^ buf[i] as u64; i += 1; }           /* 3.1s */
        // for i in range(0, len) { self.hash = (33u64 * self.hash) ^ buf[i] as u64 }        /* 3.6s */
        // for i in range(0, buf.len()) { self.hash = (33u64 * self.hash) ^ buf[i] as u64 }  /* 3.6s */
        // for byte in buf.iter() { self.hash = (33u64 * self.hash) ^ *byte as u64 }         /* 3.8s */
    }
    fn flush(&mut self) { }
}

/* Original hash function */
// fn djbhash(bytes : &[u8]) -> u64 {
//     let mut hash = 5381u64;
//     for byte in bytes.iter() {
//             hash = (33u64 * hash) ^ *byte as u64;
//     }
//     return hash;
// }

/* ----------------------------------------------- */

// This is an implementation of the Container, Mutable, Map, and
// MutableMap traits based on the DJB hash and Python's dictionaries.
// See:
//
// * http://stackoverflow.com/questions/327311/how-are-pythons-built-in-dictionaries-implemented
//   (especially the links in the first answer),
//
// * http://www.laurentluce.com/posts/python-dictionary-implementation/
//
// * http://pybites.blogspot.com/2008/10/pure-python-dictionary-implementation.html

static PERTURB_SHIFT : uint = 5;

enum Entry<K,V> {
    Empty,                      // This slot is empty
    Full(K,V),                  // This slot is holding a key and value
    Ghost(K),                   // This slot once held key k
}

impl<K : Eq, V> Entry<K,V> {
    fn is_empty(&self) -> bool { match *self { Empty => true, _ => false } }
    fn is_full(&self)  -> bool { match *self { Full(*) => true, _ => false } }
    fn is_ghost(&self) -> bool { match *self { Ghost(*) => true, _ => false } }

    #[inline]
    fn matches(&self, key : &K) -> bool {
        match *self {
            Empty                        => true,
            Full(ref k,_) | Ghost(ref k) => k == key,
        }
    }
}

pub struct HashMap<K,V> {
    table      : ~[Entry<K,V>],
    capacity   : uint,
    mask       : u64,
    length     : uint,
    ghosts     : uint,
//    collisions : uint,
}

impl<K : Eq + IterBytes,V> HashMap<K,V> {
    pub fn new() -> HashMap<K,V> { HashMap::with_capacity(8) }

    pub fn with_capacity(sz : uint) -> HashMap<K,V> {
        let capacity = uint::next_power_of_two(sz);
        HashMap {
            table : vec::from_fn(capacity, |_| Empty),
            capacity : capacity,
            mask : (capacity as u64) - 1,
            length : 0,
            ghosts : 0,
//            collisions : 0,
        }
    }

    pub fn capacity(&self) -> uint { self.capacity }
//     pub fn collisions(&self) -> uint { self.collisions }

    // This algorithm gleefully stolen from Python
    #[inline]
    fn probe(&self, key : &K) -> uint {
        let mut hash = DJBState::djbhash(key);
        let mut free = None;
        let mut i = hash & self.mask;
        while !self.table[i].matches(key) {
            if free.is_none() && self.table[i].is_ghost() { free = Some(i); }
            i = ((5 * i) + 1 + hash) & self.mask;
            hash = hash >> PERTURB_SHIFT;
        }
        if self.table[i].is_full() || free.is_none() {
            i as uint
        } else {
            free.unwrap() as uint
        }
    }

    // #[inline]
    // fn probe_mut(&mut self, key : &K) -> uint {
    //     let mut hash = DJBState::djbhash(key);
    //     let mut free = None;
    //     let mut i = hash & self.mask;
    //     while !self.table[i].matches(key) {
    //         self.collisions += 1;
    //         if free.is_none() && self.table[i].is_ghost() { free = Some(i); }
    //         i = ((5 * i) + 1 + hash) & self.mask;
    //         hash = hash >> PERTURB_SHIFT;
    //     }
    //     if self.table[i].is_full() || free.is_none() {
    //         i as uint
    //     } else {
    //         free.unwrap() as uint
    //     }
    // }

    #[inline]
    fn do_expand(&mut self, new_capacity : uint) {
        let mut new_tbl = HashMap::with_capacity( new_capacity );
        for elt in self.table.mut_iter() {
            match util::replace(elt, Empty) {
                Full(k,v)        => { new_tbl.insert(k,v); },
                Empty | Ghost(_) => { },
            }
        }
        // Copy new table's elements into self.  Note: attempting
        // to do this more directly causes: "use of partially moved
        // value"
        let cap = new_tbl.capacity;
        let mask = new_tbl.mask;
        let len = new_tbl.length;
        let ghosts = new_tbl.ghosts;
        self.table = new_tbl.table;
        self.capacity = cap;
        self.mask = mask;
        self.length = len;
        self.ghosts = ghosts;
    }

    #[inline]
    fn expand(&mut self) {
        if self.length * 3 > self.capacity * 2 {
            // Expand table if live entries nearing capacity
            self.do_expand( self.capacity * 2 );
        } else if (self.length + self.ghosts) * 3 >= self.capacity * 2 {
            // Rehash to flush out excess ghosts
            self.do_expand( self.capacity );
        }
    }
}

impl<K,V> Container for HashMap<K,V> {
    fn len(&self) -> uint { self.length }
}

impl<K,V> Mutable for HashMap<K,V> {
    fn clear(&mut self) {
        for elt in self.table.mut_iter() { *elt = Empty; }
        self.length = 0;
        self.ghosts = 0;
    }
}

impl<K : Eq + IterBytes,V> Map<K,V> for HashMap<K,V> {
    fn find<'a>(&'a self, key: &K) -> Option<&'a V> {
        let i = self.probe(key);
        match self.table[i] {
            Empty | Ghost(_) => None,
            Full(_, ref val) => Some(val),
        }
    }
}

impl<K : Eq + IterBytes,V> MutableMap<K,V> for HashMap<K,V> {

    fn swap(&mut self, key: K, value: V) -> Option<V> {
        self.expand();
        let i = self.probe(&key);
//        let i = self.probe_mut(&key);
        match self.table[i] {
            Empty => {
                self.table[i] = Full(key,value);
                self.length += 1;
                None
            },
            Ghost(_) => {
                self.table[i] = Full(key,value);
                self.length += 1;
                self.ghosts -= 1;
                None
            },
            Full(_,ref mut v) => {
                Some( util::replace(v, value) )
            },
        }
    }

    fn pop(&mut self, key: &K) -> Option<V> {
        self.expand();
        let i = self.probe(key);
        let (result,replacement) = match util::replace(&mut self.table[i], Empty) {
            Empty     => (None,Empty),
            Ghost(k)  => (None,Ghost(k)),
            Full(k,v) => {
                self.length -= 1;
                self.ghosts += 1;
                (Some(v),Ghost(k))
            },
        };
        self.table[i] = replacement;
        result
    }

    fn find_mut<'a>(&'a mut self, key: &K) -> Option<&'a mut V> {
        let i = self.probe(key);
        match self.table[i] {
            Empty | Ghost(_)  => None,
            Full(_,ref mut val) => Some(val),
        }
    }
}

/* ----------------------------------------------- */

pub struct HashSet<T> {
    priv map : HashMap<T,()>
}

impl<T : Eq + IterBytes> HashSet<T> {
    pub fn new() -> HashSet<T> { HashSet { map : HashMap::new() } }
}

impl<T> Container for HashSet<T> {
    fn len(&self) -> uint { self.map.len() }
}

impl<T> Mutable for HashSet<T> {
    fn clear(&mut self) { self.map.clear() }
}

impl<T : Eq + IterBytes> Set<T> for HashSet<T> {
    fn contains(&self, elt : &T) -> bool { self.map.contains_key(elt) }

    fn is_disjoint(&self, other : &HashSet<T>) -> bool {
        for elt in self.map.table.iter() {
            match *elt {
                Full(ref k,_) => {
                    if other.contains(k) { return false; }
                },
                _ => { },
            }
        }
        return true;
    }

    fn is_subset(&self, other : &HashSet<T>) -> bool {
        for elt in self.map.table.iter() {
            match *elt {
                Full(ref k,_) => {
                    if !other.contains(k) { return false; }
                },
                _ => { },
            }
        }
        return true;
    }

    fn is_superset(&self, other : &HashSet<T>) -> bool {
        other.is_subset(self)
    }
}

impl<T : Eq + IterBytes> MutableSet<T> for HashSet<T> {
    fn insert(&mut self, value: T) -> bool {
        self.map.insert(value,())
    }

    fn remove(&mut self, value: &T) -> bool {
        self.map.remove(value)
    }
}

/* ----------------------------------------------- */

#[cfg(test)]
mod tests {
    extern mod extra;

    use super::*;

    #[test]
    fn test_empty() {
        let m : HashMap<uint,uint> = HashMap::new();
        assert_eq!(m.len(), 0);
        assert_eq!(m.capacity(), 8);
        assert_eq!(m.find(&1), None);
    }

    #[test]
    fn test_one() {
        let mut m : HashMap<uint,uint> = HashMap::new();
        assert_eq!(m.len(), 0);
        assert!(m.insert(1,400));
        assert_eq!(m.len(), 1);
        assert_eq!(m.capacity(), 8);
        match m.find(&1) {
            Some(y) => assert_eq!(*y,400),
            None => fail!("failure!")
        }
        match m.find_mut(&1) {
            Some(y) => *y = 500,
            _ => fail!("failed!")
        }
        match m.find(&1) {
            Some(y) => assert_eq!(*y,500),
            None => fail!("failure again!")
        }
        match m.pop(&1) {
            Some(y) => assert_eq!(y,500),
            None => fail!("oh, noes!")
        }
        assert_eq!(m.len(), 0);
    }

    #[test]
    fn test_eight() {
        let mut m : HashMap<uint,uint> = HashMap::new();
        let v = [1,3,5,7,9,11,13,15];
        for i in v.iter() {
            assert!(m.insert(*i,100 * *i));
        }
        assert_eq!(m.len(),8);
        assert_eq!(m.capacity(),16);
        assert!( !m.insert(3, 12000) );
    }

    #[bench]
    fn hash_bench_siphash(b: &mut extra::test::BenchHarness) {
        let s = "abcdefghijklmnopqrstuvwxyz";
        do b.iter { s.hash(); }
    }

    #[bench]
    fn hash_bench_djbhash(b: &mut extra::test::BenchHarness) {
        let s = "abcdefghijklmnopqrstuvwxyz";
        do b.iter { DJBState::djbhash(&s); }
    }
}
<commit_msg>clean up source<commit_after>// Copyright 2013 Tommy M. McGuire
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#[ link(name = "fashhashmap", vers="1.0") ];
#[ crate_type = "lib" ];

use std::rt::io::Writer;
use std::to_bytes::IterBytes;
use std::vec;
use std::uint;
use std::util;

// Simple Writer/IterBytes based implementation of the DJB hash
// (See http://cr.yp.to/cdb/cdb.txt and http://www.cse.yorku.ca/~oz/hash.html)
struct DJBState {
    hash : u64
}

impl DJBState {
    fn new() -> DJBState { DJBState { hash : 5381u64 } }

    #[inline]
    fn djbhash<T:IterBytes>(t : &T) -> u64 {
        let mut state = DJBState::new();
        t.iter_bytes(true, |b| { state.write(b); true });
        state.flush();
        return state.hash();
    }

    fn hash(&self) -> u64 { self.hash }
}

impl Writer for DJBState {
    #[inline]
    fn write(&mut self, buf : &[u8]) {
        let len = buf.len();
        let mut i = 0;
        while i < len { self.hash = (33u64 * self.hash) ^ buf[i] as u64; i += 1; }
    }
    fn flush(&mut self) { }
}

/* ----------------------------------------------- */

// This is an implementation of the Container, Mutable, Map, and
// MutableMap traits based on the DJB hash and Python's dictionaries.
// See:
//
// * http://stackoverflow.com/questions/327311/how-are-pythons-built-in-dictionaries-implemented
//   (especially the links in the first answer),
//
// * http://www.laurentluce.com/posts/python-dictionary-implementation/
//
// * http://pybites.blogspot.com/2008/10/pure-python-dictionary-implementation.html

static PERTURB_SHIFT : uint = 5;

enum Entry<K,V> {
    Empty,                      // This slot is empty
    Full(K,V),                  // This slot is holding a key and value
    Ghost(K),                   // This slot once held key k
}

impl<K : Eq, V> Entry<K,V> {
    fn is_empty(&self) -> bool { match *self { Empty => true, _ => false } }
    fn is_full(&self)  -> bool { match *self { Full(*) => true, _ => false } }
    fn is_ghost(&self) -> bool { match *self { Ghost(*) => true, _ => false } }

    #[inline]
    fn matches(&self, key : &K) -> bool {
        match *self {
            Empty                        => true,
            Full(ref k,_) | Ghost(ref k) => k == key,
        }
    }
}

pub struct HashMap<K,V> {
    table      : ~[Entry<K,V>],
    capacity   : uint,
    mask       : u64,
    length     : uint,
    ghosts     : uint,
}

impl<K : Eq + IterBytes,V> HashMap<K,V> {
    pub fn new() -> HashMap<K,V> { HashMap::with_capacity(8) }

    pub fn with_capacity(sz : uint) -> HashMap<K,V> {
        let capacity = uint::next_power_of_two(sz);
        HashMap {
            table : vec::from_fn(capacity, |_| Empty),
            capacity : capacity,
            mask : (capacity as u64) - 1,
            length : 0,
            ghosts : 0,
        }
    }

    pub fn capacity(&self) -> uint { self.capacity }

    // This algorithm gleefully stolen from Python
    #[inline]
    fn probe(&self, key : &K) -> uint {
        let mut hash = DJBState::djbhash(key);
        let mut free = None;
        let mut i = hash & self.mask;
        while !self.table[i].matches(key) {
            if free.is_none() && self.table[i].is_ghost() { free = Some(i); }
            i = ((5 * i) + 1 + hash) & self.mask;
            hash = hash >> PERTURB_SHIFT;
        }
        if self.table[i].is_full() || free.is_none() {
            i as uint
        } else {
            free.unwrap() as uint
        }
    }

    #[inline]
    fn do_expand(&mut self, new_capacity : uint) {
        let mut new_tbl = HashMap::with_capacity( new_capacity );
        for elt in self.table.mut_iter() {
            match util::replace(elt, Empty) {
                Full(k,v)        => { new_tbl.insert(k,v); },
                Empty | Ghost(_) => { },
            }
        }
        // Copy new table's elements into self.  Note: attempting
        // to do this more directly causes: "use of partially moved
        // value"
        let cap = new_tbl.capacity;
        let mask = new_tbl.mask;
        let len = new_tbl.length;
        let ghosts = new_tbl.ghosts;
        self.table = new_tbl.table;
        self.capacity = cap;
        self.mask = mask;
        self.length = len;
        self.ghosts = ghosts;
    }

    #[inline]
    fn expand(&mut self) {
        if self.length * 3 > self.capacity * 2 {
            // Expand table if live entries nearing capacity
            self.do_expand( self.capacity * 2 );
        } else if (self.length + self.ghosts) * 3 >= self.capacity * 2 {
            // Rehash to flush out excess ghosts
            self.do_expand( self.capacity );
        }
    }
}

impl<K,V> Container for HashMap<K,V> {
    fn len(&self) -> uint { self.length }
}

impl<K,V> Mutable for HashMap<K,V> {
    fn clear(&mut self) {
        for elt in self.table.mut_iter() { *elt = Empty; }
        self.length = 0;
        self.ghosts = 0;
    }
}

impl<K : Eq + IterBytes,V> Map<K,V> for HashMap<K,V> {
    fn find<'a>(&'a self, key: &K) -> Option<&'a V> {
        let i = self.probe(key);
        match self.table[i] {
            Empty | Ghost(_) => None,
            Full(_, ref val) => Some(val),
        }
    }
}

impl<K : Eq + IterBytes,V> MutableMap<K,V> for HashMap<K,V> {

    fn swap(&mut self, key: K, value: V) -> Option<V> {
        self.expand();
        let i = self.probe(&key);
        match self.table[i] {
            Empty => {
                self.table[i] = Full(key,value);
                self.length += 1;
                None
            },
            Ghost(_) => {
                self.table[i] = Full(key,value);
                self.length += 1;
                self.ghosts -= 1;
                None
            },
            Full(_,ref mut v) => {
                Some( util::replace(v, value) )
            },
        }
    }

    fn pop(&mut self, key: &K) -> Option<V> {
        self.expand();
        let i = self.probe(key);
        let (result,replacement) = match util::replace(&mut self.table[i], Empty) {
            Empty     => (None,Empty),
            Ghost(k)  => (None,Ghost(k)),
            Full(k,v) => {
                self.length -= 1;
                self.ghosts += 1;
                (Some(v),Ghost(k))
            },
        };
        self.table[i] = replacement;
        result
    }

    fn find_mut<'a>(&'a mut self, key: &K) -> Option<&'a mut V> {
        let i = self.probe(key);
        match self.table[i] {
            Empty | Ghost(_)  => None,
            Full(_,ref mut val) => Some(val),
        }
    }
}

/* ----------------------------------------------- */

pub struct HashSet<T> {
    priv map : HashMap<T,()>
}

impl<T : Eq + IterBytes> HashSet<T> {
    pub fn new() -> HashSet<T> { HashSet { map : HashMap::new() } }
}

impl<T> Container for HashSet<T> {
    fn len(&self) -> uint { self.map.len() }
}

impl<T> Mutable for HashSet<T> {
    fn clear(&mut self) { self.map.clear() }
}

impl<T : Eq + IterBytes> Set<T> for HashSet<T> {
    fn contains(&self, elt : &T) -> bool { self.map.contains_key(elt) }

    fn is_disjoint(&self, other : &HashSet<T>) -> bool {
        for elt in self.map.table.iter() {
            match *elt {
                Full(ref k,_) => {
                    if other.contains(k) { return false; }
                },
                _ => { },
            }
        }
        return true;
    }

    fn is_subset(&self, other : &HashSet<T>) -> bool {
        for elt in self.map.table.iter() {
            match *elt {
                Full(ref k,_) => {
                    if !other.contains(k) { return false; }
                },
                _ => { },
            }
        }
        return true;
    }

    fn is_superset(&self, other : &HashSet<T>) -> bool {
        other.is_subset(self)
    }
}

impl<T : Eq + IterBytes> MutableSet<T> for HashSet<T> {
    fn insert(&mut self, value: T) -> bool {
        self.map.insert(value,())
    }

    fn remove(&mut self, value: &T) -> bool {
        self.map.remove(value)
    }
}

/* ----------------------------------------------- */

#[cfg(test)]
mod tests {
    extern mod extra;

    use super::*;

    #[test]
    fn test_empty() {
        let m : HashMap<uint,uint> = HashMap::new();
        assert_eq!(m.len(), 0);
        assert_eq!(m.capacity(), 8);
        assert_eq!(m.find(&1), None);
    }

    #[test]
    fn test_one() {
        let mut m : HashMap<uint,uint> = HashMap::new();
        assert_eq!(m.len(), 0);
        assert!(m.insert(1,400));
        assert_eq!(m.len(), 1);
        assert_eq!(m.capacity(), 8);
        match m.find(&1) {
            Some(y) => assert_eq!(*y,400),
            None => fail!("failure!")
        }
        match m.find_mut(&1) {
            Some(y) => *y = 500,
            _ => fail!("failed!")
        }
        match m.find(&1) {
            Some(y) => assert_eq!(*y,500),
            None => fail!("failure again!")
        }
        match m.pop(&1) {
            Some(y) => assert_eq!(y,500),
            None => fail!("oh, noes!")
        }
        assert_eq!(m.len(), 0);
    }

    #[test]
    fn test_eight() {
        let mut m : HashMap<uint,uint> = HashMap::new();
        let v = [1,3,5,7,9,11,13,15];
        for i in v.iter() {
            assert!(m.insert(*i,100 * *i));
        }
        assert_eq!(m.len(),8);
        assert_eq!(m.capacity(),16);
        assert!( !m.insert(3, 12000) );
    }

    #[bench]
    fn hash_bench_siphash(b: &mut extra::test::BenchHarness) {
        let s = "abcdefghijklmnopqrstuvwxyz";
        do b.iter { s.hash(); }
    }

    #[bench]
    fn hash_bench_djbhash(b: &mut extra::test::BenchHarness) {
        let s = "abcdefghijklmnopqrstuvwxyz";
        do b.iter { DJBState::djbhash(&s); }
    }
}
<|endoftext|>