<commit_before>/* Copyright 2016 Jordan Miner
 *
 * Licensed under the MIT license <LICENSE or
 * http://opensource.org/licenses/MIT>. This file may not be copied,
 * modified, or distributed except according to those terms.
 */

use std::ptr;
use iup_sys::*;
use smallvec::SmallVec;
use super::{
    Control,
    UnwrapHandle,
};
use super::attributes::{
    str_to_c_vec,
};
use super::callbacks::{
    MenuCommonCallbacks,
};
use super::containers::{
    Container,
    wrapper_to_handle_vec,
};
use super::handle_rc::HandleRc;

/// Implemented by controls that can be added as children of a `Menu`.
pub trait MenuSubitem : Control {
}

#[derive(Clone)]
pub struct Menu(HandleRc);

impl Menu {
    pub fn new() -> Self {
        unsafe {
            ::iup_open();
            // You can pass NULL for the array, even though the docs don't explicitly mention it.
            // (They only say to use NULL as the last element of the array.)
            let handle = IupMenuv(ptr::null_mut());
            Menu(HandleRc::new(handle))
        }
    }

    pub fn with_children(children: &[&MenuSubitem]) -> Self {
        unsafe {
            // got to already be IupOpen()ed
            let mut handles = wrapper_to_handle_vec(children);
            Menu::from_handles(handles.as_mut_ptr())
        }
    }

    pub unsafe fn from_handles(children: *mut *mut Ihandle) -> Self {
        let handle = IupMenuv(children);
        Menu(HandleRc::new(handle))
    }
}

impl_control_traits!(Menu);

impl Container for Menu {}

impl MenuCommonCallbacks for Menu {}

#[derive(Clone)]
pub struct Submenu(HandleRc);

impl Submenu {
    pub fn with_menu(menu: &Menu) -> Self {
        unsafe {
            ::iup_open();
            let ih = IupSubmenu(ptr::null_mut(), menu.handle());
            Submenu(HandleRc::new(ih))
        }
    }

    pub fn with_title_and_menu(title: &str, menu: &Menu) -> Self {
        unsafe {
            ::iup_open();
            let mut buf = SmallVec::<[u8; 32]>::new(); // TODO: change to 64 after upgrading smallvec
            let c_title = str_to_c_vec(title, &mut buf);
            let ih = IupSubmenu(c_title, menu.handle());
            Submenu(HandleRc::new(ih))
        }
    }
}

impl_control_traits!(Submenu);

impl MenuSubitem for Submenu {
}

#[derive(Clone)]
pub struct Item(HandleRc);

impl Item {
    pub fn new() -> Self {
        unsafe {
            ::iup_open();
            let ih = IupItem(ptr::null_mut(), ptr::null_mut());
            Item(HandleRc::new(ih))
        }
    }

    pub fn with_title(title: &str) -> Self {
        unsafe {
            ::iup_open();
            let mut buf = SmallVec::<[u8; 32]>::new(); // TODO: change to 64 after upgrading smallvec
            let c_title = str_to_c_vec(title, &mut buf);
            let ih = IupItem(c_title, ptr::null_mut());
            Item(HandleRc::new(ih))
        }
    }
}

impl_control_traits!(Item);

impl MenuSubitem for Item {
}

#[derive(Clone)]
pub struct Separator(HandleRc);

impl Separator {
    pub fn new() -> Self {
        unsafe {
            ::iup_open();
            let ih = IupSeparator();
            Separator(HandleRc::new(ih))
        }
    }
}

impl_control_traits!(Separator);

impl MenuSubitem for Separator {
}
<commit_msg>Add action event on menu Item<commit_after>/* Copyright 2016 Jordan Miner
 *
 * Licensed under the MIT license <LICENSE or
 * http://opensource.org/licenses/MIT>. This file may not be copied,
 * modified, or distributed except according to those terms.
 */

use std::ptr;
use std::ops::CoerceUnsized;
use iup_sys::*;
use libc::c_int;
use smallvec::SmallVec;
use super::{
    Control,
    UnwrapHandle,
};
use super::attributes::{
    str_to_c_vec,
};
use super::callbacks::{
    Event,
    Token,
    CallbackRegistry,
    simple_callback,
    MenuCommonCallbacks,
};
use super::containers::{
    Container,
    wrapper_to_handle_vec,
};
use super::handle_rc::HandleRc;

/// Implemented by controls that can be added as children of a `Menu`.
pub trait MenuSubitem : Control {
}

#[derive(Clone)]
pub struct Menu(HandleRc);

impl Menu {
    pub fn new() -> Self {
        unsafe {
            ::iup_open();
            // You can pass NULL for the array, even though the docs don't explicitly mention it.
            // (They only say to use NULL as the last element of the array.)
            let handle = IupMenuv(ptr::null_mut());
            Menu(HandleRc::new(handle))
        }
    }

    pub fn with_children(children: &[&MenuSubitem]) -> Self {
        unsafe {
            // got to already be IupOpen()ed
            let mut handles = wrapper_to_handle_vec(children);
            Menu::from_handles(handles.as_mut_ptr())
        }
    }

    pub unsafe fn from_handles(children: *mut *mut Ihandle) -> Self {
        let handle = IupMenuv(children);
        Menu(HandleRc::new(handle))
    }
}

impl_control_traits!(Menu);

impl Container for Menu {}

impl MenuCommonCallbacks for Menu {}

#[derive(Clone)]
pub struct Submenu(HandleRc);

impl Submenu {
    pub fn with_menu(menu: &Menu) -> Self {
        unsafe {
            ::iup_open();
            let ih = IupSubmenu(ptr::null_mut(), menu.handle());
            Submenu(HandleRc::new(ih))
        }
    }

    pub fn with_title_and_menu(title: &str, menu: &Menu) -> Self {
        unsafe {
            ::iup_open();
            let mut buf = SmallVec::<[u8; 32]>::new(); // TODO: change to 64 after upgrading smallvec
            let c_title = str_to_c_vec(title, &mut buf);
            let ih = IupSubmenu(c_title, menu.handle());
            Submenu(HandleRc::new(ih))
        }
    }
}

impl_control_traits!(Submenu);

impl MenuSubitem for Submenu {}

#[derive(Clone)]
pub struct Item(HandleRc);

impl Item {
    pub fn new() -> Self {
        unsafe {
            ::iup_open();
            let ih = IupItem(ptr::null_mut(), ptr::null_mut());
            Item(HandleRc::new(ih))
        }
    }

    pub fn with_title(title: &str) -> Self {
        unsafe {
            ::iup_open();
            let mut buf = SmallVec::<[u8; 32]>::new(); // TODO: change to 64 after upgrading smallvec
            let c_title = str_to_c_vec(title, &mut buf);
            let ih = IupItem(c_title, ptr::null_mut());
            Item(HandleRc::new(ih))
        }
    }

    pub fn action_event<'a>(&'a self) -> Event<'a, FnMut(), ItemActionCallbackToken>
    where &'a Self: CoerceUnsized<&'a Control> {
        Event::new(self as &'a Control, &ITEM_ACTION_CALLBACKS)
    }
}

impl_control_traits!(Item);

impl MenuSubitem for Item {}

callback_token!(ItemActionCallbackToken);
thread_local!(
    static ITEM_ACTION_CALLBACKS: CallbackRegistry<FnMut(), ItemActionCallbackToken> =
        CallbackRegistry::new("ACTION", item_action_cb)
);
extern fn item_action_cb(ih: *mut Ihandle) -> c_int {
    simple_callback(ih, &ITEM_ACTION_CALLBACKS)
}

#[derive(Clone)]
pub struct Separator(HandleRc);

impl Separator {
    pub fn new() -> Self {
        unsafe {
            ::iup_open();
            let ih = IupSeparator();
            Separator(HandleRc::new(ih))
        }
    }
}

impl_control_traits!(Separator);

impl MenuSubitem for Separator {}
<|endoftext|>


<commit_before>//! A module with ide helpers for high-level ide features.
pub mod famous_defs;
pub mod generated_lints;
pub mod import_assets;
pub mod insert_use;
pub mod merge_imports;
pub mod insert_whitespace_into_node;
pub mod node_ext;
pub mod rust_doc;

use std::{collections::VecDeque, iter};

use base_db::FileId;
use hir::{ItemInNs, MacroDef, ModuleDef, Name, PathResolution, Semantics};
use itertools::Itertools;
use syntax::{
    ast::{self, make, HasLoopBody, Ident},
    AstNode, AstToken, Direction, SyntaxElement, SyntaxKind, SyntaxToken, TokenAtOffset, WalkEvent,
    T,
};

use crate::{defs::Definition, RootDatabase};

pub use self::famous_defs::FamousDefs;

pub fn item_name(db: &RootDatabase, item: ItemInNs) -> Option<Name> {
    match item {
        ItemInNs::Types(module_def_id) => ModuleDef::from(module_def_id).name(db),
        ItemInNs::Values(module_def_id) => ModuleDef::from(module_def_id).name(db),
        ItemInNs::Macros(macro_def_id) => MacroDef::from(macro_def_id).name(db),
    }
}

/// Parses and returns the derive path at the cursor position in the given attribute, if it is a derive.
/// This special case is required because the derive macro is a compiler builtin that discards the input derives.
///
/// The returned path is synthesized from TokenTree tokens and as such cannot be used with the [`Semantics`].
pub fn get_path_in_derive_attr(
    sema: &hir::Semantics<RootDatabase>,
    attr: &ast::Attr,
    cursor: &Ident,
) -> Option<ast::Path> {
    let path = attr.path()?;
    let tt = attr.token_tree()?;
    if !tt.syntax().text_range().contains_range(cursor.syntax().text_range()) {
        return None;
    }
    let scope = sema.scope(attr.syntax());
    let resolved_attr = sema.resolve_path(&path)?;
    let derive = FamousDefs(sema, scope.krate()).core_macros_builtin_derive()?;
    if PathResolution::Macro(derive) != resolved_attr {
        return None;
    }
    get_path_at_cursor_in_tt(cursor)
}

/// Parses the path the identifier is part of inside a token tree.
pub fn get_path_at_cursor_in_tt(cursor: &Ident) -> Option<ast::Path> {
    let cursor = cursor.syntax();
    let first = cursor
        .siblings_with_tokens(Direction::Prev)
        .filter_map(SyntaxElement::into_token)
        .take_while(|tok| tok.kind() != T!['('] && tok.kind() != T![,])
        .last()?;
    let path_tokens = first
        .siblings_with_tokens(Direction::Next)
        .filter_map(SyntaxElement::into_token)
        .take_while(|tok| tok != cursor);

    ast::Path::parse(&path_tokens.chain(iter::once(cursor.clone())).join("")).ok()
}

/// Parses and resolves the path at the cursor position in the given attribute, if it is a derive.
/// This special case is required because the derive macro is a compiler builtin that discards the input derives.
pub fn try_resolve_derive_input(
    sema: &hir::Semantics<RootDatabase>,
    attr: &ast::Attr,
    cursor: &Ident,
) -> Option<PathResolution> {
    let path = get_path_in_derive_attr(sema, attr, cursor)?;
    let scope = sema.scope(attr.syntax());
    // FIXME: This double resolve shouldn't be necessary
    // It's only here so we prefer macros over other namespaces
    match scope.speculative_resolve_as_mac(&path) {
        Some(mac) if mac.kind() == hir::MacroKind::Derive => Some(PathResolution::Macro(mac)),
        Some(_) => return None,
        None => scope
            .speculative_resolve(&path)
            .filter(|res| matches!(res, PathResolution::Def(ModuleDef::Module(_)))),
    }
}

/// Picks the token with the highest rank returned by the passed in function.
pub fn pick_best_token(
    tokens: TokenAtOffset<SyntaxToken>,
    f: impl Fn(SyntaxKind) -> usize,
) -> Option<SyntaxToken> {
    tokens.max_by_key(move |t| f(t.kind()))
}

/// Converts the mod path struct into its ast representation.
pub fn mod_path_to_ast(path: &hir::ModPath) -> ast::Path {
    let _p = profile::span("mod_path_to_ast");

    let mut segments = Vec::new();
    let mut is_abs = false;
    match path.kind {
        hir::PathKind::Plain => {}
        hir::PathKind::Super(0) => segments.push(make::path_segment_self()),
        hir::PathKind::Super(n) => segments.extend((0..n).map(|_| make::path_segment_super())),
        hir::PathKind::DollarCrate(_) | hir::PathKind::Crate => {
            segments.push(make::path_segment_crate())
        }
        hir::PathKind::Abs => is_abs = true,
    }

    segments.extend(
        path.segments()
            .iter()
            .map(|segment| make::path_segment(make::name_ref(&segment.to_smol_str()))),
    );
    make::path_from_segments(segments, is_abs)
}

/// Iterates all `ModuleDef`s and `Impl` blocks of the given file.
pub fn visit_file_defs(
    sema: &Semantics<RootDatabase>,
    file_id: FileId,
    cb: &mut dyn FnMut(Definition),
) {
    let db = sema.db;
    let module = match sema.to_module_def(file_id) {
        Some(it) => it,
        None => return,
    };
    let mut defs: VecDeque<_> = module.declarations(db).into();
    while let Some(def) = defs.pop_front() {
        if let ModuleDef::Module(submodule) = def {
            if let hir::ModuleSource::Module(_) = submodule.definition_source(db).value {
                defs.extend(submodule.declarations(db));
                submodule.impl_defs(db).into_iter().for_each(|impl_| cb(impl_.into()));
            }
        }
        cb(def.into());
    }
    module.impl_defs(db).into_iter().for_each(|impl_| cb(impl_.into()));
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct SnippetCap {
    _private: (),
}

impl SnippetCap {
    pub const fn new(allow_snippets: bool) -> Option<SnippetCap> {
        if allow_snippets {
            Some(SnippetCap { _private: () })
        } else {
            None
        }
    }
}

/// Calls `cb` on each expression inside `expr` that is at "tail position".
/// Does not walk into `break` or `return` expressions.
/// Note that modifying the tree while iterating it will cause undefined iteration which might
/// potentially results in an out of bounds panic.
pub fn for_each_tail_expr(expr: &ast::Expr, cb: &mut dyn FnMut(&ast::Expr)) {
    match expr {
        ast::Expr::BlockExpr(b) => {
            match b.modifier() {
                Some(
                    ast::BlockModifier::Async(_)
                    | ast::BlockModifier::Try(_)
                    | ast::BlockModifier::Const(_),
                ) => return cb(expr),

                Some(ast::BlockModifier::Label(label)) => {
                    for_each_break_expr(Some(label), b.stmt_list(), &mut |b| {
                        cb(&ast::Expr::BreakExpr(b))
                    });
                }
                Some(ast::BlockModifier::Unsafe(_)) => (),
                None => (),
            }
            if let Some(stmt_list) = b.stmt_list() {
                if let Some(e) = stmt_list.tail_expr() {
                    for_each_tail_expr(&e, cb);
                }
            }
        }
        ast::Expr::IfExpr(if_) => {
            let mut if_ = if_.clone();
            loop {
                if let Some(block) = if_.then_branch() {
                    for_each_tail_expr(&ast::Expr::BlockExpr(block), cb);
                }
                match if_.else_branch() {
                    Some(ast::ElseBranch::IfExpr(it)) => if_ = it,
                    Some(ast::ElseBranch::Block(block)) => {
                        for_each_tail_expr(&ast::Expr::BlockExpr(block), cb);
                        break;
                    }
                    None => break,
                }
            }
        }
        ast::Expr::LoopExpr(l) => {
            for_each_break_expr(l.label(), l.loop_body().and_then(|it| it.stmt_list()), &mut |b| {
                cb(&ast::Expr::BreakExpr(b))
            })
        }
        ast::Expr::MatchExpr(m) => {
            if let Some(arms) = m.match_arm_list() {
                arms.arms().filter_map(|arm| arm.expr()).for_each(|e| for_each_tail_expr(&e, cb));
            }
        }
        ast::Expr::ArrayExpr(_)
        | ast::Expr::AwaitExpr(_)
        | ast::Expr::BinExpr(_)
        | ast::Expr::BoxExpr(_)
        | ast::Expr::BreakExpr(_)
        | ast::Expr::CallExpr(_)
        | ast::Expr::CastExpr(_)
        | ast::Expr::ClosureExpr(_)
        | ast::Expr::ContinueExpr(_)
        | ast::Expr::FieldExpr(_)
        | ast::Expr::ForExpr(_)
        | ast::Expr::IndexExpr(_)
        | ast::Expr::Literal(_)
        | ast::Expr::MacroCall(_)
        | ast::Expr::MacroStmts(_)
        | ast::Expr::MethodCallExpr(_)
        | ast::Expr::ParenExpr(_)
        | ast::Expr::PathExpr(_)
        | ast::Expr::PrefixExpr(_)
        | ast::Expr::RangeExpr(_)
        | ast::Expr::RecordExpr(_)
        | ast::Expr::RefExpr(_)
        | ast::Expr::ReturnExpr(_)
        | ast::Expr::TryExpr(_)
        | ast::Expr::TupleExpr(_)
        | ast::Expr::WhileExpr(_)
        | ast::Expr::YieldExpr(_) => cb(expr),
    }
}

/// Calls `cb` on each break expr inside of `body` that is applicable for the given label.
pub fn for_each_break_expr(
    label: Option<ast::Label>,
    body: Option<ast::StmtList>,
    cb: &mut dyn FnMut(ast::BreakExpr),
) {
    let label = label.and_then(|lbl| lbl.lifetime());
    let mut depth = 0;
    if let Some(b) = body {
        let preorder = &mut b.syntax().preorder();
        let ev_as_expr = |ev| match ev {
            WalkEvent::Enter(it) => Some(WalkEvent::Enter(ast::Expr::cast(it)?)),
            WalkEvent::Leave(it) => Some(WalkEvent::Leave(ast::Expr::cast(it)?)),
        };
        let eq_label = |lt: Option<ast::Lifetime>| {
            lt.zip(label.as_ref()).map_or(false, |(lt, lbl)| lt.text() == lbl.text())
        };
        while let Some(node) = preorder.find_map(ev_as_expr) {
            match node {
                WalkEvent::Enter(expr) => match expr {
                    ast::Expr::LoopExpr(_) | ast::Expr::WhileExpr(_) | ast::Expr::ForExpr(_) => {
                        depth += 1
                    }
                    ast::Expr::BlockExpr(e) if e.label().is_some() => depth += 1,
                    ast::Expr::BreakExpr(b)
                        if (depth == 0 && b.lifetime().is_none()) || eq_label(b.lifetime()) =>
                    {
                        cb(b);
                    }
                    _ => (),
                },
                WalkEvent::Leave(expr) => match expr {
                    ast::Expr::LoopExpr(_) | ast::Expr::WhileExpr(_) | ast::Expr::ForExpr(_) => {
                        depth -= 1
                    }
                    ast::Expr::BlockExpr(e) if e.label().is_some() => depth -= 1,
                    _ => (),
                },
            }
        }
    }
}

/// Checks if the given lint is equal or is contained by the other lint which may or may not be a group.
pub fn lint_eq_or_in_group(lint: &str, lint_is: &str) -> bool {
    if lint == lint_is {
        return true;
    }

    if let Some(group) = generated_lints::DEFAULT_LINT_GROUPS
        .iter()
        .chain(generated_lints::CLIPPY_LINT_GROUPS.iter())
        .chain(generated_lints::RUSTDOC_LINT_GROUPS.iter())
        .find(|&check| check.lint.label == lint_is)
    {
        group.children.contains(&lint)
    } else {
        false
    }
}

/// Parses the input token tree as comma separated plain paths.
pub fn parse_tt_as_comma_sep_paths(input: ast::TokenTree) -> Option<Vec<ast::Path>> {
    let r_paren = input.r_paren_token();
    let tokens =
        input.syntax().children_with_tokens().skip(1).map_while(|it| match it.into_token() {
            // seeing a keyword means the attribute is unclosed so stop parsing here
            Some(tok) if tok.kind().is_keyword() => None,
            // don't include the right token tree parenthesis if it exists
            tok @ Some(_) if tok == r_paren => None,
            // only nodes that we can find are other TokenTrees, those are unexpected in this parse though
            None => None,
            Some(tok) => Some(tok),
        });
    let input_expressions = tokens.into_iter().group_by(|tok| tok.kind() == T![,]);
    let paths = input_expressions
        .into_iter()
        .filter_map(|(is_sep, group)| (!is_sep).then(|| group))
        .filter_map(|mut tokens| ast::Path::parse(&tokens.join("")).ok())
        .collect();
    Some(paths)
}
<commit_msg>import style<commit_after>//! A module with ide helpers for high-level ide features.
pub mod famous_defs;
pub mod generated_lints;
pub mod import_assets;
pub mod insert_use;
pub mod merge_imports;
pub mod insert_whitespace_into_node;
pub mod node_ext;
pub mod rust_doc;

use std::{collections::VecDeque, iter};

use base_db::FileId;
use hir::{ItemInNs, MacroDef, ModuleDef, Name, PathResolution, Semantics};
use itertools::Itertools;
use syntax::{
    ast::{self, make, HasLoopBody},
    AstNode, AstToken, Direction, SyntaxElement, SyntaxKind, SyntaxToken, TokenAtOffset, WalkEvent,
    T,
};

use crate::{defs::Definition, RootDatabase};

pub use self::famous_defs::FamousDefs;

pub fn item_name(db: &RootDatabase, item: ItemInNs) -> Option<Name> {
    match item {
        ItemInNs::Types(module_def_id) => ModuleDef::from(module_def_id).name(db),
        ItemInNs::Values(module_def_id) => ModuleDef::from(module_def_id).name(db),
        ItemInNs::Macros(macro_def_id) => MacroDef::from(macro_def_id).name(db),
    }
}

/// Parses and returns the derive path at the cursor position in the given attribute, if it is a derive.
/// This special case is required because the derive macro is a compiler builtin that discards the input derives.
///
/// The returned path is synthesized from TokenTree tokens and as such cannot be used with the [`Semantics`].
pub fn get_path_in_derive_attr(
    sema: &hir::Semantics<RootDatabase>,
    attr: &ast::Attr,
    cursor: &ast::Ident,
) -> Option<ast::Path> {
    let path = attr.path()?;
    let tt = attr.token_tree()?;
    if !tt.syntax().text_range().contains_range(cursor.syntax().text_range()) {
        return None;
    }
    let scope = sema.scope(attr.syntax());
    let resolved_attr = sema.resolve_path(&path)?;
    let derive = FamousDefs(sema, scope.krate()).core_macros_builtin_derive()?;
    if PathResolution::Macro(derive) != resolved_attr {
        return None;
    }
    get_path_at_cursor_in_tt(cursor)
}

/// Parses the path the identifier is part of inside a token tree.
pub fn get_path_at_cursor_in_tt(cursor: &ast::Ident) -> Option<ast::Path> {
    let cursor = cursor.syntax();
    let first = cursor
        .siblings_with_tokens(Direction::Prev)
        .filter_map(SyntaxElement::into_token)
        .take_while(|tok| tok.kind() != T!['('] && tok.kind() != T![,])
        .last()?;
    let path_tokens = first
        .siblings_with_tokens(Direction::Next)
        .filter_map(SyntaxElement::into_token)
        .take_while(|tok| tok != cursor);

    ast::Path::parse(&path_tokens.chain(iter::once(cursor.clone())).join("")).ok()
}

/// Parses and resolves the path at the cursor position in the given attribute, if it is a derive.
/// This special case is required because the derive macro is a compiler builtin that discards the input derives.
pub fn try_resolve_derive_input(
    sema: &hir::Semantics<RootDatabase>,
    attr: &ast::Attr,
    cursor: &ast::Ident,
) -> Option<PathResolution> {
    let path = get_path_in_derive_attr(sema, attr, cursor)?;
    let scope = sema.scope(attr.syntax());
    // FIXME: This double resolve shouldn't be necessary
    // It's only here so we prefer macros over other namespaces
    match scope.speculative_resolve_as_mac(&path) {
        Some(mac) if mac.kind() == hir::MacroKind::Derive => Some(PathResolution::Macro(mac)),
        Some(_) => return None,
        None => scope
            .speculative_resolve(&path)
            .filter(|res| matches!(res, PathResolution::Def(ModuleDef::Module(_)))),
    }
}

/// Picks the token with the highest rank returned by the passed in function.
pub fn pick_best_token(
    tokens: TokenAtOffset<SyntaxToken>,
    f: impl Fn(SyntaxKind) -> usize,
) -> Option<SyntaxToken> {
    tokens.max_by_key(move |t| f(t.kind()))
}

/// Converts the mod path struct into its ast representation.
pub fn mod_path_to_ast(path: &hir::ModPath) -> ast::Path {
    let _p = profile::span("mod_path_to_ast");

    let mut segments = Vec::new();
    let mut is_abs = false;
    match path.kind {
        hir::PathKind::Plain => {}
        hir::PathKind::Super(0) => segments.push(make::path_segment_self()),
        hir::PathKind::Super(n) => segments.extend((0..n).map(|_| make::path_segment_super())),
        hir::PathKind::DollarCrate(_) | hir::PathKind::Crate => {
            segments.push(make::path_segment_crate())
        }
        hir::PathKind::Abs => is_abs = true,
    }

    segments.extend(
        path.segments()
            .iter()
            .map(|segment| make::path_segment(make::name_ref(&segment.to_smol_str()))),
    );
    make::path_from_segments(segments, is_abs)
}

/// Iterates all `ModuleDef`s and `Impl` blocks of the given file.
pub fn visit_file_defs(
    sema: &Semantics<RootDatabase>,
    file_id: FileId,
    cb: &mut dyn FnMut(Definition),
) {
    let db = sema.db;
    let module = match sema.to_module_def(file_id) {
        Some(it) => it,
        None => return,
    };
    let mut defs: VecDeque<_> = module.declarations(db).into();
    while let Some(def) = defs.pop_front() {
        if let ModuleDef::Module(submodule) = def {
            if let hir::ModuleSource::Module(_) = submodule.definition_source(db).value {
                defs.extend(submodule.declarations(db));
                submodule.impl_defs(db).into_iter().for_each(|impl_| cb(impl_.into()));
            }
        }
        cb(def.into());
    }
    module.impl_defs(db).into_iter().for_each(|impl_| cb(impl_.into()));
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct SnippetCap {
    _private: (),
}

impl SnippetCap {
    pub const fn new(allow_snippets: bool) -> Option<SnippetCap> {
        if allow_snippets {
            Some(SnippetCap { _private: () })
        } else {
            None
        }
    }
}

/// Calls `cb` on each expression inside `expr` that is at "tail position".
/// Does not walk into `break` or `return` expressions.
/// Note that modifying the tree while iterating it will cause undefined iteration which might
/// potentially results in an out of bounds panic.
pub fn for_each_tail_expr(expr: &ast::Expr, cb: &mut dyn FnMut(&ast::Expr)) {
    match expr {
        ast::Expr::BlockExpr(b) => {
            match b.modifier() {
                Some(
                    ast::BlockModifier::Async(_)
                    | ast::BlockModifier::Try(_)
                    | ast::BlockModifier::Const(_),
                ) => return cb(expr),

                Some(ast::BlockModifier::Label(label)) => {
                    for_each_break_expr(Some(label), b.stmt_list(), &mut |b| {
                        cb(&ast::Expr::BreakExpr(b))
                    });
                }
                Some(ast::BlockModifier::Unsafe(_)) => (),
                None => (),
            }
            if let Some(stmt_list) = b.stmt_list() {
                if let Some(e) = stmt_list.tail_expr() {
                    for_each_tail_expr(&e, cb);
                }
            }
        }
        ast::Expr::IfExpr(if_) => {
            let mut if_ = if_.clone();
            loop {
                if let Some(block) = if_.then_branch() {
                    for_each_tail_expr(&ast::Expr::BlockExpr(block), cb);
                }
                match if_.else_branch() {
                    Some(ast::ElseBranch::IfExpr(it)) => if_ = it,
                    Some(ast::ElseBranch::Block(block)) => {
                        for_each_tail_expr(&ast::Expr::BlockExpr(block), cb);
                        break;
                    }
                    None => break,
                }
            }
        }
        ast::Expr::LoopExpr(l) => {
            for_each_break_expr(l.label(), l.loop_body().and_then(|it| it.stmt_list()), &mut |b| {
                cb(&ast::Expr::BreakExpr(b))
            })
        }
        ast::Expr::MatchExpr(m) => {
            if let Some(arms) = m.match_arm_list() {
                arms.arms().filter_map(|arm| arm.expr()).for_each(|e| for_each_tail_expr(&e, cb));
            }
        }
        ast::Expr::ArrayExpr(_)
        | ast::Expr::AwaitExpr(_)
        | ast::Expr::BinExpr(_)
        | ast::Expr::BoxExpr(_)
        | ast::Expr::BreakExpr(_)
        | ast::Expr::CallExpr(_)
        | ast::Expr::CastExpr(_)
        | ast::Expr::ClosureExpr(_)
        | ast::Expr::ContinueExpr(_)
        | ast::Expr::FieldExpr(_)
        | ast::Expr::ForExpr(_)
        | ast::Expr::IndexExpr(_)
        | ast::Expr::Literal(_)
        | ast::Expr::MacroCall(_)
        | ast::Expr::MacroStmts(_)
        | ast::Expr::MethodCallExpr(_)
        | ast::Expr::ParenExpr(_)
        | ast::Expr::PathExpr(_)
        | ast::Expr::PrefixExpr(_)
        | ast::Expr::RangeExpr(_)
        | ast::Expr::RecordExpr(_)
        | ast::Expr::RefExpr(_)
        | ast::Expr::ReturnExpr(_)
        | ast::Expr::TryExpr(_)
        | ast::Expr::TupleExpr(_)
        | ast::Expr::WhileExpr(_)
        | ast::Expr::YieldExpr(_) => cb(expr),
    }
}

/// Calls `cb` on each break expr inside of `body` that is applicable for the given label.
pub fn for_each_break_expr(
    label: Option<ast::Label>,
    body: Option<ast::StmtList>,
    cb: &mut dyn FnMut(ast::BreakExpr),
) {
    let label = label.and_then(|lbl| lbl.lifetime());
    let mut depth = 0;
    if let Some(b) = body {
        let preorder = &mut b.syntax().preorder();
        let ev_as_expr = |ev| match ev {
            WalkEvent::Enter(it) => Some(WalkEvent::Enter(ast::Expr::cast(it)?)),
            WalkEvent::Leave(it) => Some(WalkEvent::Leave(ast::Expr::cast(it)?)),
        };
        let eq_label = |lt: Option<ast::Lifetime>| {
            lt.zip(label.as_ref()).map_or(false, |(lt, lbl)| lt.text() == lbl.text())
        };
        while let Some(node) = preorder.find_map(ev_as_expr) {
            match node {
                WalkEvent::Enter(expr) => match expr {
                    ast::Expr::LoopExpr(_) | ast::Expr::WhileExpr(_) | ast::Expr::ForExpr(_) => {
                        depth += 1
                    }
                    ast::Expr::BlockExpr(e) if e.label().is_some() => depth += 1,
                    ast::Expr::BreakExpr(b)
                        if (depth == 0 && b.lifetime().is_none()) || eq_label(b.lifetime()) =>
                    {
                        cb(b);
                    }
                    _ => (),
                },
                WalkEvent::Leave(expr) => match expr {
                    ast::Expr::LoopExpr(_) | ast::Expr::WhileExpr(_) | ast::Expr::ForExpr(_) => {
                        depth -= 1
                    }
                    ast::Expr::BlockExpr(e) if e.label().is_some() => depth -= 1,
                    _ => (),
                },
            }
        }
    }
}

/// Checks if the given lint is equal or is contained by the other lint which may or may not be a group.
pub fn lint_eq_or_in_group(lint: &str, lint_is: &str) -> bool {
    if lint == lint_is {
        return true;
    }

    if let Some(group) = generated_lints::DEFAULT_LINT_GROUPS
        .iter()
        .chain(generated_lints::CLIPPY_LINT_GROUPS.iter())
        .chain(generated_lints::RUSTDOC_LINT_GROUPS.iter())
        .find(|&check| check.lint.label == lint_is)
    {
        group.children.contains(&lint)
    } else {
        false
    }
}

/// Parses the input token tree as comma separated plain paths.
pub fn parse_tt_as_comma_sep_paths(input: ast::TokenTree) -> Option<Vec<ast::Path>> {
    let r_paren = input.r_paren_token();
    let tokens =
        input.syntax().children_with_tokens().skip(1).map_while(|it| match it.into_token() {
            // seeing a keyword means the attribute is unclosed so stop parsing here
            Some(tok) if tok.kind().is_keyword() => None,
            // don't include the right token tree parenthesis if it exists
            tok @ Some(_) if tok == r_paren => None,
            // only nodes that we can find are other TokenTrees, those are unexpected in this parse though
            None => None,
            Some(tok) => Some(tok),
        });
    let input_expressions = tokens.into_iter().group_by(|tok| tok.kind() == T![,]);
    let paths = input_expressions
        .into_iter()
        .filter_map(|(is_sep, group)| (!is_sep).then(|| group))
        .filter_map(|mut tokens| ast::Path::parse(&tokens.join("")).ok())
        .collect();
    Some(paths)
}
<|endoftext|>


<commit_before>#![feature(test)]

#[macro_use]
extern crate generic_array;
extern crate test;
extern crate rand;
extern crate typenum;
extern crate spatial;

use rand::Rng;
use test::Bencher;
use spatial::{Point, Rect, MbrQuery, RStar, RStarTree};
use typenum::U3;

fn generate_tree_with_size(count: usize) -> RStarTree<f64, U3, Point<f64, U3>, usize>
{
    let mut tree_map = RStar::new_with_max(512);
    let mut rng = rand::thread_rng();
    for i in 0..count {
        tree_map.insert(Point::new(arr![f64; rng.next_f64(), rng.next_f64(), rng.next_f64()]), i);
    }
    tree_map
}

#[bench]
fn insert_rng_bench_3d_10(b: &mut Bencher) {
    b.iter( || {
        generate_tree_with_size(10);
    });
}

#[bench]
fn insert_rng_bench_3d_100(b: &mut Bencher) {
    b.iter( || {
        generate_tree_with_size(100);
    });
}

#[bench]
fn insert_rng_bench_3d_1000(b: &mut Bencher) {
    b.iter( || {
        generate_tree_with_size(1000);
    });
}

#[bench]
fn insert_rng_bench_3d_10000(b: &mut Bencher) {
    b.iter( || {
        generate_tree_with_size(10000);
    });
}

fn search_rng_bench_3d(b: &mut Bencher, size: usize) {
    let tree_map = generate_tree_with_size(size);
    let mut rng = rand::thread_rng();
    b.iter( || {
        let x_array = arr![f64; rng.next_f64(), rng.next_f64(), rng.next_f64()];
        let y_array = arr![f64; rng.next_f64(), rng.next_f64(), rng.next_f64()];
        tree_map.iter_query(MbrQuery::Overlaps(Rect::from_corners(x_array,y_array)))
            .count();
    });
}

fn remove_rng_bench_3d(b: &mut Bencher, size: usize) {
    let mut tree_map = generate_tree_with_size(size);
    let mut rng = rand::thread_rng();
    b.iter( || {
        let x_array = arr![f64; rng.next_f64(), rng.next_f64(), rng.next_f64()];
        let y_array = arr![f64; rng.next_f64(), rng.next_f64(), rng.next_f64()];
        tree_map.remove(MbrQuery::Overlaps(Rect::from_corners(x_array,y_array)));
    });
}

#[bench]
fn search_bench_3d_10(b: &mut Bencher) {
    search_rng_bench_3d(b, 10);

}

#[bench]
fn search_bench_3d_100(b: &mut Bencher) {
    search_rng_bench_3d(b, 100);
}

#[bench]
fn search_bench_3d_1000(b: &mut Bencher) {
    search_rng_bench_3d(b, 1000);
}

#[bench]
fn search_bench_3d_10000(b: &mut Bencher) {
    search_rng_bench_3d(b, 10000);
}

#[bench]
fn remove_bench_3d_10(b: &mut Bencher) {
    remove_rng_bench_3d(b, 10);

}

#[bench]
fn remove_bench_3d_100(b: &mut Bencher) {
    remove_rng_bench_3d(b, 100);
}

#[bench]
fn remove_bench_3d_1000(b: &mut Bencher) {
    remove_rng_bench_3d(b, 1000);
}

#[bench]
fn remove_bench_3d_10000(b: &mut Bencher) {
    remove_rng_bench_3d(b, 10000);
}<commit_msg>Made remove re-insert the leaves.<commit_after>#![feature(test)]

#[macro_use]
extern crate generic_array;
extern crate test;
extern crate rand;
extern crate typenum;
extern crate spatial;

use rand::Rng;
use test::Bencher;
use spatial::{Point, Rect, MbrQuery, RStar, RStarTree};
use typenum::U3;

fn generate_tree_with_size(count: usize) -> RStarTree<f64, U3, Point<f64, U3>, usize>
{
    let mut tree_map = RStar::new_with_max(512);
    let mut rng = rand::thread_rng();
    for i in 0..count {
        tree_map.insert(Point::new(arr![f64; rng.next_f64(), rng.next_f64(), rng.next_f64()]), i);
    }
    tree_map
}

#[bench]
fn insert_rng_bench_3d_10(b: &mut Bencher) {
    b.iter( || {
        generate_tree_with_size(10);
    });
}

#[bench]
fn insert_rng_bench_3d_100(b: &mut Bencher) {
    b.iter( || {
        generate_tree_with_size(100);
    });
}

#[bench]
fn insert_rng_bench_3d_1000(b: &mut Bencher) {
    b.iter( || {
        generate_tree_with_size(1000);
    });
}

#[bench]
fn insert_rng_bench_3d_10000(b: &mut Bencher) {
    b.iter( || {
        generate_tree_with_size(10000);
    });
}

fn search_rng_bench_3d(b: &mut Bencher, size: usize) {
    let tree_map = generate_tree_with_size(size);
    let mut rng = rand::thread_rng();
    b.iter( || {
        let x_array = arr![f64; rng.next_f64(), rng.next_f64(), rng.next_f64()];
        let y_array = arr![f64; rng.next_f64(), rng.next_f64(), rng.next_f64()];
        tree_map.iter_query(MbrQuery::Overlaps(Rect::from_corners(x_array,y_array)))
            .count();
    });
}

fn remove_rng_bench_3d(b: &mut Bencher, size: usize) {
    let mut tree_map = generate_tree_with_size(size);
    let mut rng = rand::thread_rng();
    b.iter( || {
        let x_array = arr![f64; rng.next_f64(), rng.next_f64(), rng.next_f64()];
        let y_array = arr![f64; rng.next_f64(), rng.next_f64(), rng.next_f64()];
        let removed = tree_map.remove(MbrQuery::Overlaps(Rect::from_corners(x_array,y_array)));
        for(lshape, item) in removed {
            tree_map.insert(lshape, item);
        }
    });
}

#[bench]
fn search_bench_3d_10(b: &mut Bencher) {
    search_rng_bench_3d(b, 10);

}

#[bench]
fn search_bench_3d_100(b: &mut Bencher) {
    search_rng_bench_3d(b, 100);
}

#[bench]
fn search_bench_3d_1000(b: &mut Bencher) {
    search_rng_bench_3d(b, 1000);
}

#[bench]
fn search_bench_3d_10000(b: &mut Bencher) {
    search_rng_bench_3d(b, 10000);
}

#[bench]
fn remove_bench_3d_10(b: &mut Bencher) {
    remove_rng_bench_3d(b, 10);

}

#[bench]
fn remove_bench_3d_100(b: &mut Bencher) {
    remove_rng_bench_3d(b, 100);
}

#[bench]
fn remove_bench_3d_1000(b: &mut Bencher) {
    remove_rng_bench_3d(b, 1000);
}

#[bench]
fn remove_bench_3d_10000(b: &mut Bencher) {
    remove_rng_bench_3d(b, 10000);
}<|endoftext|>


<commit_before>use std::{io::Cursor, path::Path};

use rocksdb::{
    merge_operator::MergeFn, BlockBasedIndexType, BlockBasedOptions, ColumnFamily,
    ColumnFamilyDescriptor, IteratorMode, MergeOperands, Options, ReadOptions, SliceTransform,
    WriteBatch, DB,
};

use crate::model::{
    GameId, Key, KeyPrefix, LichessEntry, LichessGame, MastersEntry, MastersGame, Month,
    PlayerEntry, PlayerStatus, UserId, Year,
};

#[derive(Debug)]
pub struct Database {
    pub inner: DB,
}

fn column_family(
    name: &str,
    merge: Option<&str>,
    merge_fn: impl MergeFn + Clone,
    prefix: Option<usize>,
    block_size: usize,
    bloom_filter: i32,
) -> ColumnFamilyDescriptor {
    let mut opts = Options::default();
    if let Some(merge) = merge {
        opts.set_merge_operator_associative(merge, merge_fn);
    }
    opts.set_prefix_extractor(match prefix {
        Some(prefix) => SliceTransform::create_fixed_prefix(prefix),
        None => SliceTransform::create_noop(),
    });
    let mut block_opts = BlockBasedOptions::default();
    block_opts.set_index_type(BlockBasedIndexType::HashSearch);
    block_opts.set_block_size(block_size);
    if bloom_filter > 0 {
        block_opts.set_bloom_filter(bloom_filter, true);
    }
    opts.set_block_based_table_factory(&block_opts);
    ColumnFamilyDescriptor::new(name, opts)
}

impl Database {
    pub fn open<P: AsRef<Path>>(path: P) -> Result<Database, rocksdb::Error> {
        let mut db_opts = Options::default();
        db_opts.create_if_missing(true);
        db_opts.create_missing_column_families(true);

        let inner = DB::open_cf_descriptors(
            &db_opts,
            path,
            vec![
                // Masters database
                column_family(
                    "masters",
                    Some("masters_merge"),
                    masters_merge,
                    Some(KeyPrefix::SIZE),
                    8 * 1024,
                    3,
                ),
                column_family("masters_game", None, void_merge, None, 4 * 1024, 0),
                // Lichess database
                column_family(
                    "lichess",
                    Some("lichess_merge"),
                    lichess_merge,
                    Some(KeyPrefix::SIZE),
                    16 * 1024,
                    2,
                ),
                column_family(
                    "lichess_game",
                    Some("lichess_game_merge"),
                    lichess_game_merge,
                    None,
                    4 * 1024,
                    0,
                ),
                // Player database (also shares lichess_game)
                column_family(
                    "player",
                    Some("player_merge"),
                    player_merge,
                    Some(KeyPrefix::SIZE),
                    16 * 1024,
                    2,
                ),
                column_family("player_status", None, void_merge, None, 4 * 1024, 0),
            ],
        )?;

        Ok(Database { inner })
    }

    pub fn masters(&self) -> MastersDatabase<'_> {
        MastersDatabase {
            inner: &self.inner,
            cf_masters: self.inner.cf_handle("masters").expect("cf masters"),
            cf_masters_game: self
                .inner
                .cf_handle("masters_game")
                .expect("cf masters_game"),
        }
    }

    pub fn lichess(&self) -> LichessDatabase<'_> {
        LichessDatabase {
            inner: &self.inner,
            cf_lichess: self.inner.cf_handle("lichess").expect("cf lichess"),
            cf_lichess_game: self
                .inner
                .cf_handle("lichess_game")
                .expect("cf lichess_game"),

            cf_player: self.inner.cf_handle("player").expect("cf player"),
            cf_player_status: self
                .inner
                .cf_handle("player_status")
                .expect("cf player_status"),
        }
    }
}

pub struct MastersDatabase<'a> {
    inner: &'a DB,
    cf_masters: &'a ColumnFamily,
    cf_masters_game: &'a ColumnFamily,
}

impl MastersDatabase<'_> {
    pub fn has_game(&self, id: GameId) -> Result<bool, rocksdb::Error> {
        self.inner
            .get_cf(self.cf_masters_game, id.to_bytes())
            .map(|maybe_entry| maybe_entry.is_some())
    }

    pub fn game(&self, id: GameId) -> Result<Option<MastersGame>, rocksdb::Error> {
        Ok(self
            .inner
            .get_cf(self.cf_masters_game, id.to_bytes())?
            .map(|buf| serde_json::from_slice(&buf).expect("deserialize masters game")))
    }

    pub fn has(&self, key: Key) -> Result<bool, rocksdb::Error> {
        self.inner
            .get_cf(self.cf_masters, key.into_bytes())
            .map(|maybe_entry| maybe_entry.is_some())
    }

    pub fn read(
        &self,
        key: KeyPrefix,
        since: Year,
        until: Year,
    ) -> Result<MastersEntry, rocksdb::Error> {
        tokio::task::block_in_place(move || {
            let mut opt = ReadOptions::default();
            opt.set_prefix_same_as_start(true);
            opt.set_iterate_lower_bound(key.with_year(since).into_bytes());
            opt.set_iterate_upper_bound(key.with_year(until.add_years_saturating(1)).into_bytes());

            let iterator = self
                .inner
                .iterator_cf_opt(self.cf_masters, opt, IteratorMode::Start);

            let mut entry = MastersEntry::default();
            for (_key, value) in iterator {
                let mut cursor = Cursor::new(value);
                entry
                    .extend_from_reader(&mut cursor)
                    .expect("deserialize masters entry");
            }

            Ok(entry)
        })
    }

    pub fn batch(&self) -> MastersBatch<'_> {
        MastersBatch {
            db: self,
            batch: WriteBatch::default(),
        }
    }
}

pub struct MastersBatch<'a> {
    db: &'a MastersDatabase<'a>,
    batch: WriteBatch,
}

impl MastersBatch<'_> {
    pub fn merge(&mut self, key: Key, entry: MastersEntry) {
        let mut cursor = Cursor::new(Vec::with_capacity(MastersEntry::SIZE_HINT));
        entry.write(&mut cursor).expect("serialize masters entry");
        self.batch
            .merge_cf(self.db.cf_masters, key.into_bytes(), cursor.into_inner());
    }

    pub fn put_game(&mut self, id: GameId, game: &MastersGame) {
        self.batch.put_cf(
            self.db.cf_masters_game,
            id.to_bytes(),
            serde_json::to_vec(game).expect("serialize masters game"),
        );
    }

    pub fn commit(self) -> Result<(), rocksdb::Error> {
        tokio::task::block_in_place(move || self.db.inner.write(self.batch))
    }
}

pub struct LichessDatabase<'a> {
    inner: &'a DB,
    cf_lichess: &'a ColumnFamily,
    cf_lichess_game: &'a ColumnFamily,

    cf_player: &'a ColumnFamily,
    cf_player_status: &'a ColumnFamily,
}

impl LichessDatabase<'_> {
    pub fn game(&self, id: GameId) -> Result<Option<LichessGame>, rocksdb::Error> {
        Ok(self
            .inner
            .get_cf(self.cf_lichess_game, id.to_bytes())?
            .map(|buf| {
                let mut cursor = Cursor::new(buf);
                LichessGame::read(&mut cursor).expect("deserialize game info")
            }))
    }

    pub fn read_lichess(
        &self,
        key: &KeyPrefix,
        since: Month,
        until: Month,
    ) -> Result<LichessEntry, rocksdb::Error> {
        tokio::task::block_in_place(move || {
            let mut opt = ReadOptions::default();
            opt.set_prefix_same_as_start(true);
            opt.set_iterate_lower_bound(key.with_month(since).into_bytes());
            opt.set_iterate_upper_bound(
                key.with_month(until.add_months_saturating(1)).into_bytes(),
            );

            let iterator = self
                .inner
                .iterator_cf_opt(self.cf_lichess, opt, IteratorMode::Start);

            let mut entry = LichessEntry::default();
            for (_key, value) in iterator {
                let mut cursor = Cursor::new(value);
                entry
                    .extend_from_reader(&mut cursor)
                    .expect("deserialize lichess entry");
            }

            Ok(entry)
        })
    }

    pub fn read_player(
        &self,
        key: &KeyPrefix,
        since: Month,
        until: Month,
    ) -> Result<PlayerEntry, rocksdb::Error> {
        tokio::task::block_in_place(move || {
            let mut opt = ReadOptions::default();
            opt.set_prefix_same_as_start(true);
            opt.set_iterate_lower_bound(key.with_month(since).into_bytes());
            opt.set_iterate_upper_bound(
                key.with_month(until.add_months_saturating(1)).into_bytes(),
            );

            let iterator = self
                .inner
                .iterator_cf_opt(self.cf_player, opt, IteratorMode::Start);

            let mut entry = PlayerEntry::default();
            for (_key, value) in iterator {
                let mut cursor = Cursor::new(value);
                entry
                    .extend_from_reader(&mut cursor)
                    .expect("deserialize player entry");
            }

            Ok(entry)
        })
    }

    pub fn player_status(&self, id: &UserId) -> Result<Option<PlayerStatus>, rocksdb::Error> {
        Ok(self
            .inner
            .get_cf(self.cf_player_status, id.as_lowercase_str())?
            .map(|buf| {
                let mut cursor = Cursor::new(buf);
                PlayerStatus::read(&mut cursor).expect("deserialize status")
            }))
    }

    pub fn put_player_status(
        &self,
        id: &UserId,
        status: &PlayerStatus,
    ) -> Result<(), rocksdb::Error> {
        let mut cursor = Cursor::new(Vec::with_capacity(PlayerStatus::SIZE_HINT));
        status.write(&mut cursor).expect("serialize status");
        self.inner.put_cf(
            self.cf_player_status,
            id.as_lowercase_str(),
            cursor.into_inner(),
        )
    }

    pub fn batch(&self) -> LichessBatch<'_> {
        LichessBatch {
            inner: self,
            batch: WriteBatch::default(),
        }
    }
}

pub struct LichessBatch<'a> {
    inner: &'a LichessDatabase<'a>,
    batch: WriteBatch,
}

impl LichessBatch<'_> {
    pub fn merge_lichess(&mut self, key: Key, entry: LichessEntry) {
        let mut cursor = Cursor::new(Vec::with_capacity(LichessEntry::SIZE_HINT));
        entry.write(&mut cursor).expect("serialize lichess entry");
        self.batch
            .merge_cf(self.inner.cf_lichess, key.into_bytes(), cursor.into_inner());
    }

    pub fn merge_game(&mut self, id: GameId, info: LichessGame) {
        let mut cursor = Cursor::new(Vec::with_capacity(LichessGame::SIZE_HINT));
        info.write(&mut cursor).expect("serialize game info");
        self.batch.merge_cf(
            self.inner.cf_lichess_game,
            id.to_bytes(),
            cursor.into_inner(),
        );
    }

    pub fn merge_player(&mut self, key: Key, entry: PlayerEntry) {
        let mut cursor = Cursor::new(Vec::with_capacity(PlayerEntry::SIZE_HINT));
        entry.write(&mut cursor).expect("serialize player entry");
        self.batch
            .merge_cf(self.inner.cf_player, key.into_bytes(), cursor.into_inner());
    }

    pub fn commit(self) -> Result<(), rocksdb::Error> {
        tokio::task::block_in_place(|| self.inner.inner.write(self.batch))
    }
}

fn lichess_merge(
    _key: &[u8],
    existing: Option<&[u8]>,
    operands: &mut MergeOperands,
) -> Option<Vec<u8>> {
    let mut entry = LichessEntry::default();
    let mut size_hint = 0;
    for op in existing.into_iter().chain(operands.into_iter()) {
        let mut cursor = Cursor::new(op);
        entry
            .extend_from_reader(&mut cursor)
            .expect("deserialize for lichess merge");
        size_hint += op.len();
    }
    let mut cursor = Cursor::new(Vec::with_capacity(size_hint));
    entry.write(&mut cursor).expect("write lichess entry");
    Some(cursor.into_inner())
}

fn lichess_game_merge(
    _key: &[u8],
    existing: Option<&[u8]>,
    operands: &mut MergeOperands,
) -> Option<Vec<u8>> {
    // Take latest game info, but merge index status.
    let mut info: Option<LichessGame> = None;
    let mut size_hint = 0;
    for op in existing.into_iter().chain(operands.into_iter()) {
        let mut cursor = Cursor::new(op);
        let mut new_info = LichessGame::read(&mut cursor).expect("read for lichess game merge");
        if let Some(old_info) = info {
            new_info.indexed_player.white |= old_info.indexed_player.white;
            new_info.indexed_player.black |= old_info.indexed_player.black;
            new_info.indexed_lichess |= old_info.indexed_lichess;
        }
        info = Some(new_info);
        size_hint = op.len();
    }
    info.map(|info| {
        let mut cursor = Cursor::new(Vec::with_capacity(size_hint));
        info.write(&mut cursor).expect("write lichess game");
        cursor.into_inner()
    })
}

fn player_merge(
    _key: &[u8],
    existing: Option<&[u8]>,
    operands: &mut MergeOperands,
) -> Option<Vec<u8>> {
    let mut entry = PlayerEntry::default();
    let mut size_hint = 0;
    for op in existing.into_iter().chain(operands.into_iter()) {
        let mut cursor = Cursor::new(op);
        entry
            .extend_from_reader(&mut cursor)
            .expect("deserialize for player merge");
        size_hint += op.len();
    }
    let mut cursor = Cursor::new(Vec::with_capacity(size_hint));
    entry.write(&mut cursor).expect("write player entry");
    Some(cursor.into_inner())
}

fn masters_merge(
    _key: &[u8],
    existing: Option<&[u8]>,
    operands: &mut MergeOperands,
) -> Option<Vec<u8>> {
    let mut entry = MastersEntry::default();
    let mut size_hint = 0;
    for op in existing.into_iter().chain(operands.into_iter()) {
        let mut cursor = Cursor::new(op);
        entry
            .extend_from_reader(&mut cursor)
            .expect("deserialize for masters merge");
        size_hint += op.len();
    }
    let mut cursor = Cursor::new(Vec::with_capacity(size_hint));
    entry.write(&mut cursor).expect("write masters entry");
    Some(cursor.into_inner())
}

fn void_merge(
    _key: &[u8],
    _existing: Option<&[u8]>,
    _operands: &mut MergeOperands,
) -> Option<Vec<u8>> {
    unreachable!("void merge")
}
<commit_msg>Revert "experiment with marking blocking io"<commit_after>use std::{io::Cursor, path::Path};

use rocksdb::{
    merge_operator::MergeFn, BlockBasedIndexType, BlockBasedOptions, ColumnFamily,
    ColumnFamilyDescriptor, IteratorMode, MergeOperands, Options, ReadOptions, SliceTransform,
    WriteBatch, DB,
};

use crate::model::{
    GameId, Key, KeyPrefix, LichessEntry, LichessGame, MastersEntry, MastersGame, Month,
    PlayerEntry, PlayerStatus, UserId, Year,
};

#[derive(Debug)]
pub struct Database {
    pub inner: DB,
}

fn column_family(
    name: &str,
    merge: Option<&str>,
    merge_fn: impl MergeFn + Clone,
    prefix: Option<usize>,
    block_size: usize,
    bloom_filter: i32,
) -> ColumnFamilyDescriptor {
    let mut opts = Options::default();
    if let Some(merge) = merge {
        opts.set_merge_operator_associative(merge, merge_fn);
    }
    opts.set_prefix_extractor(match prefix {
        Some(prefix) => SliceTransform::create_fixed_prefix(prefix),
        None => SliceTransform::create_noop(),
    });
    let mut block_opts = BlockBasedOptions::default();
    block_opts.set_index_type(BlockBasedIndexType::HashSearch);
    block_opts.set_block_size(block_size);
    if bloom_filter > 0 {
        block_opts.set_bloom_filter(bloom_filter, true);
    }
    opts.set_block_based_table_factory(&block_opts);
    ColumnFamilyDescriptor::new(name, opts)
}

impl Database {
    pub fn open<P: AsRef<Path>>(path: P) -> Result<Database, rocksdb::Error> {
        let mut db_opts = Options::default();
        db_opts.create_if_missing(true);
        db_opts.create_missing_column_families(true);

        let inner = DB::open_cf_descriptors(
            &db_opts,
            path,
            vec![
                // Masters database
                column_family(
                    "masters",
                    Some("masters_merge"),
                    masters_merge,
                    Some(KeyPrefix::SIZE),
                    8 * 1024,
                    3,
                ),
                column_family("masters_game", None, void_merge, None, 4 * 1024, 0),
                // Lichess database
                column_family(
                    "lichess",
                    Some("lichess_merge"),
                    lichess_merge,
                    Some(KeyPrefix::SIZE),
                    16 * 1024,
                    2,
                ),
                column_family(
                    "lichess_game",
                    Some("lichess_game_merge"),
                    lichess_game_merge,
                    None,
                    4 * 1024,
                    0,
                ),
                // Player database (also shares lichess_game)
                column_family(
                    "player",
                    Some("player_merge"),
                    player_merge,
                    Some(KeyPrefix::SIZE),
                    16 * 1024,
                    2,
                ),
                column_family("player_status", None, void_merge, None, 4 * 1024, 0),
            ],
        )?;

        Ok(Database { inner })
    }

    pub fn masters(&self) -> MastersDatabase<'_> {
        MastersDatabase {
            inner: &self.inner,
            cf_masters: self.inner.cf_handle("masters").expect("cf masters"),
            cf_masters_game: self
                .inner
                .cf_handle("masters_game")
                .expect("cf masters_game"),
        }
    }

    pub fn lichess(&self) -> LichessDatabase<'_> {
        LichessDatabase {
            inner: &self.inner,
            cf_lichess: self.inner.cf_handle("lichess").expect("cf lichess"),
            cf_lichess_game: self
                .inner
                .cf_handle("lichess_game")
                .expect("cf lichess_game"),

            cf_player: self.inner.cf_handle("player").expect("cf player"),
            cf_player_status: self
                .inner
                .cf_handle("player_status")
                .expect("cf player_status"),
        }
    }
}

pub struct MastersDatabase<'a> {
    inner: &'a DB,
    cf_masters: &'a ColumnFamily,
    cf_masters_game: &'a ColumnFamily,
}

impl MastersDatabase<'_> {
    pub fn has_game(&self, id: GameId) -> Result<bool, rocksdb::Error> {
        self.inner
            .get_cf(self.cf_masters_game, id.to_bytes())
            .map(|maybe_entry| maybe_entry.is_some())
    }

    pub fn game(&self, id: GameId) -> Result<Option<MastersGame>, rocksdb::Error> {
        Ok(self
            .inner
            .get_cf(self.cf_masters_game, id.to_bytes())?
            .map(|buf| serde_json::from_slice(&buf).expect("deserialize masters game")))
    }

    pub fn has(&self, key: Key) -> Result<bool, rocksdb::Error> {
        self.inner
            .get_cf(self.cf_masters, key.into_bytes())
            .map(|maybe_entry| maybe_entry.is_some())
    }

    pub fn read(
        &self,
        key: KeyPrefix,
        since: Year,
        until: Year,
    ) -> Result<MastersEntry, rocksdb::Error> {
        let mut opt = ReadOptions::default();
        opt.set_prefix_same_as_start(true);
        opt.set_iterate_lower_bound(key.with_year(since).into_bytes());
        opt.set_iterate_upper_bound(key.with_year(until.add_years_saturating(1)).into_bytes());

        let iterator = self
            .inner
            .iterator_cf_opt(self.cf_masters, opt, IteratorMode::Start);

        let mut entry = MastersEntry::default();
        for (_key, value) in iterator {
            let mut cursor = Cursor::new(value);
            entry
                .extend_from_reader(&mut cursor)
                .expect("deserialize masters entry");
        }

        Ok(entry)
    }

    pub fn batch(&self) -> MastersBatch<'_> {
        MastersBatch {
            db: self,
            batch: WriteBatch::default(),
        }
    }
}

pub struct MastersBatch<'a> {
    db: &'a MastersDatabase<'a>,
    batch: WriteBatch,
}

impl MastersBatch<'_> {
    pub fn merge(&mut self, key: Key, entry: MastersEntry) {
        let mut cursor = Cursor::new(Vec::with_capacity(MastersEntry::SIZE_HINT));
        entry.write(&mut cursor).expect("serialize masters entry");
        self.batch
            .merge_cf(self.db.cf_masters, key.into_bytes(), cursor.into_inner());
    }

    pub fn put_game(&mut self, id: GameId, game: &MastersGame) {
        self.batch.put_cf(
            self.db.cf_masters_game,
            id.to_bytes(),
            serde_json::to_vec(game).expect("serialize masters game"),
        );
    }

    pub fn commit(self) -> Result<(), rocksdb::Error> {
        self.db.inner.write(self.batch)
    }
}

pub struct LichessDatabase<'a> {
    inner: &'a DB,
    cf_lichess: &'a ColumnFamily,
    cf_lichess_game: &'a ColumnFamily,

    cf_player: &'a ColumnFamily,
    cf_player_status: &'a ColumnFamily,
}

impl LichessDatabase<'_> {
    pub fn game(&self, id: GameId) -> Result<Option<LichessGame>, rocksdb::Error> {
        Ok(self
            .inner
            .get_cf(self.cf_lichess_game, id.to_bytes())?
            .map(|buf| {
                let mut cursor = Cursor::new(buf);
                LichessGame::read(&mut cursor).expect("deserialize game info")
            }))
    }

    pub fn read_lichess(
        &self,
        key: &KeyPrefix,
        since: Month,
        until: Month,
    ) -> Result<LichessEntry, rocksdb::Error> {
        let mut opt = ReadOptions::default();
        opt.set_prefix_same_as_start(true);
        opt.set_iterate_lower_bound(key.with_month(since).into_bytes());
        opt.set_iterate_upper_bound(key.with_month(until.add_months_saturating(1)).into_bytes());

        let iterator = self
            .inner
            .iterator_cf_opt(self.cf_lichess, opt, IteratorMode::Start);

        let mut entry = LichessEntry::default();
        for (_key, value) in iterator {
            let mut cursor = Cursor::new(value);
            entry
                .extend_from_reader(&mut cursor)
                .expect("deserialize lichess entry");
        }

        Ok(entry)
    }

    pub fn read_player(
        &self,
        key: &KeyPrefix,
        since: Month,
        until: Month,
    ) -> Result<PlayerEntry, rocksdb::Error> {
        let mut opt = ReadOptions::default();
        opt.set_prefix_same_as_start(true);
        opt.set_iterate_lower_bound(key.with_month(since).into_bytes());
        opt.set_iterate_upper_bound(key.with_month(until.add_months_saturating(1)).into_bytes());

        let iterator = self
            .inner
            .iterator_cf_opt(self.cf_player, opt, IteratorMode::Start);

        let mut entry = PlayerEntry::default();
        for (_key, value) in iterator {
            let mut cursor = Cursor::new(value);
            entry
                .extend_from_reader(&mut cursor)
                .expect("deserialize player entry");
        }

        Ok(entry)
    }

    pub fn player_status(&self, id: &UserId) -> Result<Option<PlayerStatus>, rocksdb::Error> {
        Ok(self
            .inner
            .get_cf(self.cf_player_status, id.as_lowercase_str())?
            .map(|buf| {
                let mut cursor = Cursor::new(buf);
                PlayerStatus::read(&mut cursor).expect("deserialize status")
            }))
    }

    pub fn put_player_status(
        &self,
        id: &UserId,
        status: &PlayerStatus,
    ) -> Result<(), rocksdb::Error> {
        let mut cursor = Cursor::new(Vec::with_capacity(PlayerStatus::SIZE_HINT));
        status.write(&mut cursor).expect("serialize status");
        self.inner.put_cf(
            self.cf_player_status,
            id.as_lowercase_str(),
            cursor.into_inner(),
        )
    }

    pub fn batch(&self) -> LichessBatch<'_> {
        LichessBatch {
            inner: self,
            batch: WriteBatch::default(),
        }
    }
}

pub struct LichessBatch<'a> {
    inner: &'a LichessDatabase<'a>,
    batch: WriteBatch,
}

impl LichessBatch<'_> {
    pub fn merge_lichess(&mut self, key: Key, entry: LichessEntry) {
        let mut cursor = Cursor::new(Vec::with_capacity(LichessEntry::SIZE_HINT));
        entry.write(&mut cursor).expect("serialize lichess entry");
        self.batch
            .merge_cf(self.inner.cf_lichess, key.into_bytes(), cursor.into_inner());
    }

    pub fn merge_game(&mut self, id: GameId, info: LichessGame) {
        let mut cursor = Cursor::new(Vec::with_capacity(LichessGame::SIZE_HINT));
        info.write(&mut cursor).expect("serialize game info");
        self.batch.merge_cf(
            self.inner.cf_lichess_game,
            id.to_bytes(),
            cursor.into_inner(),
        );
    }

    pub fn merge_player(&mut self, key: Key, entry: PlayerEntry) {
        let mut cursor = Cursor::new(Vec::with_capacity(PlayerEntry::SIZE_HINT));
        entry.write(&mut cursor).expect("serialize player entry");
        self.batch
            .merge_cf(self.inner.cf_player, key.into_bytes(), cursor.into_inner());
    }

    pub fn commit(self) -> Result<(), rocksdb::Error> {
        self.inner.inner.write(self.batch)
    }
}

fn lichess_merge(
    _key: &[u8],
    existing: Option<&[u8]>,
    operands: &mut MergeOperands,
) -> Option<Vec<u8>> {
    let mut entry = LichessEntry::default();
    let mut size_hint = 0;
    for op in existing.into_iter().chain(operands.into_iter()) {
        let mut cursor = Cursor::new(op);
        entry
            .extend_from_reader(&mut cursor)
            .expect("deserialize for lichess merge");
        size_hint += op.len();
    }
    let mut cursor = Cursor::new(Vec::with_capacity(size_hint));
    entry.write(&mut cursor).expect("write lichess entry");
    Some(cursor.into_inner())
}

fn lichess_game_merge(
    _key: &[u8],
    existing: Option<&[u8]>,
    operands: &mut MergeOperands,
) -> Option<Vec<u8>> {
    // Take latest game info, but merge index status.
    let mut info: Option<LichessGame> = None;
    let mut size_hint = 0;
    for op in existing.into_iter().chain(operands.into_iter()) {
        let mut cursor = Cursor::new(op);
        let mut new_info = LichessGame::read(&mut cursor).expect("read for lichess game merge");
        if let Some(old_info) = info {
            new_info.indexed_player.white |= old_info.indexed_player.white;
            new_info.indexed_player.black |= old_info.indexed_player.black;
            new_info.indexed_lichess |= old_info.indexed_lichess;
        }
        info = Some(new_info);
        size_hint = op.len();
    }
    info.map(|info| {
        let mut cursor = Cursor::new(Vec::with_capacity(size_hint));
        info.write(&mut cursor).expect("write lichess game");
        cursor.into_inner()
    })
}

fn player_merge(
    _key: &[u8],
    existing: Option<&[u8]>,
    operands: &mut MergeOperands,
) -> Option<Vec<u8>> {
    let mut entry = PlayerEntry::default();
    let mut size_hint = 0;
    for op in existing.into_iter().chain(operands.into_iter()) {
        let mut cursor = Cursor::new(op);
        entry
            .extend_from_reader(&mut cursor)
            .expect("deserialize for player merge");
        size_hint += op.len();
    }
    let mut cursor = Cursor::new(Vec::with_capacity(size_hint));
    entry.write(&mut cursor).expect("write player entry");
    Some(cursor.into_inner())
}

fn masters_merge(
    _key: &[u8],
    existing: Option<&[u8]>,
    operands: &mut MergeOperands,
) -> Option<Vec<u8>> {
    let mut entry = MastersEntry::default();
    let mut size_hint = 0;
    for op in existing.into_iter().chain(operands.into_iter()) {
        let mut cursor = Cursor::new(op);
        entry
            .extend_from_reader(&mut cursor)
            .expect("deserialize for masters merge");
        size_hint += op.len();
    }
    let mut cursor = Cursor::new(Vec::with_capacity(size_hint));
    entry.write(&mut cursor).expect("write masters entry");
    Some(cursor.into_inner())
}

fn void_merge(
    _key: &[u8],
    _existing: Option<&[u8]>,
    _operands: &mut MergeOperands,
) -> Option<Vec<u8>> {
    unreachable!("void merge")
}
<|endoftext|>


<commit_before>use crate::Bytes;
use core::fmt;
use core::marker::PhantomData;
use serde::de::{Error, Visitor};
use serde::Deserializer;

#[cfg(any(feature = "std", feature = "alloc"))]
use crate::ByteBuf;

#[cfg(any(feature = "std", feature = "alloc"))]
use core::cmp;

#[cfg(feature = "alloc")]
use alloc::borrow::Cow;
#[cfg(all(feature = "std", not(feature = "alloc")))]
use std::borrow::Cow;

#[cfg(feature = "alloc")]
use alloc::boxed::Box;
#[cfg(feature = "alloc")]
use alloc::string::String;
#[cfg(feature = "alloc")]
use alloc::vec::Vec;

#[cfg(any(feature = "std", feature = "alloc"))]
use serde::de::SeqAccess;

/// Types that can be deserialized via `#[serde(with = "serde_bytes")]`.
pub trait Deserialize<'de>: Sized {
    #[allow(missing_docs)]
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>;
}

impl<'de: 'a, 'a> Deserialize<'de> for &'a [u8] {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        // Via the serde::Deserialize impl for &[u8].
        serde::Deserialize::deserialize(deserializer)
    }
}

#[cfg(any(feature = "std", feature = "alloc"))]
impl<'de> Deserialize<'de> for Vec<u8> {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        Deserialize::deserialize(deserializer).map(ByteBuf::into_vec)
    }
}

impl<'de: 'a, 'a> Deserialize<'de> for &'a Bytes {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        Deserialize::deserialize(deserializer).map(Bytes::new)
    }
}

#[cfg(any(feature = "std", feature = "alloc"))]
impl<'de> Deserialize<'de> for ByteBuf {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        // Via the serde::Deserialize impl for ByteBuf.
        serde::Deserialize::deserialize(deserializer)
    }
}

#[cfg(any(feature = "std", feature = "alloc"))]
impl<'de: 'a, 'a> Deserialize<'de> for Cow<'a, [u8]> {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        struct CowVisitor;

        impl<'de> Visitor<'de> for CowVisitor {
            type Value = Cow<'de, [u8]>;

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                formatter.write_str("a byte array")
            }

            fn visit_borrowed_bytes<E>(self, v: &'de [u8]) -> Result<Self::Value, E>
            where
                E: Error,
            {
                Ok(Cow::Borrowed(v))
            }

            fn visit_borrowed_str<E>(self, v: &'de str) -> Result<Self::Value, E>
            where
                E: Error,
            {
                Ok(Cow::Borrowed(v.as_bytes()))
            }

            fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
            where
                E: Error,
            {
                Ok(Cow::Owned(v.to_vec()))
            }

            fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
            where
                E: Error,
            {
                Ok(Cow::Owned(v.as_bytes().to_vec()))
            }

            fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<Self::Value, E>
            where
                E: Error,
            {
                Ok(Cow::Owned(v))
            }

            fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
            where
                E: Error,
            {
                Ok(Cow::Owned(v.into_bytes()))
            }

            fn visit_seq<V>(self, mut visitor: V) -> Result<Self::Value, V::Error>
            where
                V: SeqAccess<'de>,
            {
                let len = cmp::min(visitor.size_hint().unwrap_or(0), 4096);
                let mut bytes = Vec::with_capacity(len);

                while let Some(b) = visitor.next_element()? {
                    bytes.push(b);
                }

                Ok(Cow::Owned(bytes))
            }
        }

        deserializer.deserialize_bytes(CowVisitor)
    }
}

#[cfg(any(feature = "std", feature = "alloc"))]
impl<'de: 'a, 'a> Deserialize<'de> for Cow<'a, Bytes> {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        Deserialize::deserialize(deserializer).map(Cow::Borrowed)
    }
}

#[cfg(any(feature = "std", feature = "alloc"))]
impl<'de> Deserialize<'de> for Box<[u8]> {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        Deserialize::deserialize(deserializer).map(Vec::into_boxed_slice)
    }
}

#[cfg(any(feature = "std", feature = "alloc"))]
impl<'de> Deserialize<'de> for Box<Bytes> {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        let bytes: Box<[u8]> = Deserialize::deserialize(deserializer)?;
        Ok(bytes.into())
    }
}

impl<'de, T> Deserialize<'de> for Option<T>
where
    T: Deserialize<'de>,
{
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        struct BytesVisitor<T> {
            out: PhantomData<T>,
        }

        impl<'de, T> Visitor<'de> for BytesVisitor<T>
        where
            T: Deserialize<'de>,
        {
            type Value = Option<T>;

            fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
                f.write_str("optional byte array")
            }

            fn visit_unit<E: Error>(self) -> Result<Self::Value, E> {
                Ok(None)
            }

            fn visit_none<E: Error>(self) -> Result<Self::Value, E> {
                Ok(None)
            }

            fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
            where
                D: Deserializer<'de>,
            {
                T::deserialize(deserializer).map(Some)
            }
        }

        let visitor = BytesVisitor { out: PhantomData };
        deserializer.deserialize_option(visitor)
    }
}
<commit_msg>Forward Cow<Bytes> de impl to Cow<[u8]><commit_after>use crate::Bytes;
use core::fmt;
use core::marker::PhantomData;
use serde::de::{Error, Visitor};
use serde::Deserializer;

#[cfg(any(feature = "std", feature = "alloc"))]
use crate::ByteBuf;

#[cfg(any(feature = "std", feature = "alloc"))]
use core::cmp;

#[cfg(feature = "alloc")]
use alloc::borrow::Cow;
#[cfg(all(feature = "std", not(feature = "alloc")))]
use std::borrow::Cow;

#[cfg(feature = "alloc")]
use alloc::boxed::Box;
#[cfg(feature = "alloc")]
use alloc::string::String;
#[cfg(feature = "alloc")]
use alloc::vec::Vec;

#[cfg(any(feature = "std", feature = "alloc"))]
use serde::de::SeqAccess;

/// Types that can be deserialized via `#[serde(with = "serde_bytes")]`.
pub trait Deserialize<'de>: Sized {
    #[allow(missing_docs)]
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>;
}

impl<'de: 'a, 'a> Deserialize<'de> for &'a [u8] {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        // Via the serde::Deserialize impl for &[u8].
        serde::Deserialize::deserialize(deserializer)
    }
}

#[cfg(any(feature = "std", feature = "alloc"))]
impl<'de> Deserialize<'de> for Vec<u8> {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        Deserialize::deserialize(deserializer).map(ByteBuf::into_vec)
    }
}

impl<'de: 'a, 'a> Deserialize<'de> for &'a Bytes {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        Deserialize::deserialize(deserializer).map(Bytes::new)
    }
}

#[cfg(any(feature = "std", feature = "alloc"))]
impl<'de> Deserialize<'de> for ByteBuf {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        // Via the serde::Deserialize impl for ByteBuf.
        serde::Deserialize::deserialize(deserializer)
    }
}

#[cfg(any(feature = "std", feature = "alloc"))]
impl<'de: 'a, 'a> Deserialize<'de> for Cow<'a, [u8]> {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        struct CowVisitor;

        impl<'de> Visitor<'de> for CowVisitor {
            type Value = Cow<'de, [u8]>;

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                formatter.write_str("a byte array")
            }

            fn visit_borrowed_bytes<E>(self, v: &'de [u8]) -> Result<Self::Value, E>
            where
                E: Error,
            {
                Ok(Cow::Borrowed(v))
            }

            fn visit_borrowed_str<E>(self, v: &'de str) -> Result<Self::Value, E>
            where
                E: Error,
            {
                Ok(Cow::Borrowed(v.as_bytes()))
            }

            fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
            where
                E: Error,
            {
                Ok(Cow::Owned(v.to_vec()))
            }

            fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
            where
                E: Error,
            {
                Ok(Cow::Owned(v.as_bytes().to_vec()))
            }

            fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<Self::Value, E>
            where
                E: Error,
            {
                Ok(Cow::Owned(v))
            }

            fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
            where
                E: Error,
            {
                Ok(Cow::Owned(v.into_bytes()))
            }

            fn visit_seq<V>(self, mut visitor: V) -> Result<Self::Value, V::Error>
            where
                V: SeqAccess<'de>,
            {
                let len = cmp::min(visitor.size_hint().unwrap_or(0), 4096);
                let mut bytes = Vec::with_capacity(len);

                while let Some(b) = visitor.next_element()? {
                    bytes.push(b);
                }

                Ok(Cow::Owned(bytes))
            }
        }

        deserializer.deserialize_bytes(CowVisitor)
    }
}

#[cfg(any(feature = "std", feature = "alloc"))]
impl<'de: 'a, 'a> Deserialize<'de> for Cow<'a, Bytes> {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        let cow: Cow<[u8]> = Deserialize::deserialize(deserializer)?;
        match cow {
            Cow::Borrowed(bytes) => Ok(Cow::Borrowed(Bytes::new(bytes))),
            Cow::Owned(bytes) => Ok(Cow::Owned(ByteBuf::from(bytes))),
        }
    }
}

#[cfg(any(feature = "std", feature = "alloc"))]
impl<'de> Deserialize<'de> for Box<[u8]> {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        Deserialize::deserialize(deserializer).map(Vec::into_boxed_slice)
    }
}

#[cfg(any(feature = "std", feature = "alloc"))]
impl<'de> Deserialize<'de> for Box<Bytes> {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        let bytes: Box<[u8]> = Deserialize::deserialize(deserializer)?;
        Ok(bytes.into())
    }
}

impl<'de, T> Deserialize<'de> for Option<T>
where
    T: Deserialize<'de>,
{
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        struct BytesVisitor<T> {
            out: PhantomData<T>,
        }

        impl<'de, T> Visitor<'de> for BytesVisitor<T>
        where
            T: Deserialize<'de>,
        {
            type Value = Option<T>;

            fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
                f.write_str("optional byte array")
            }

            fn visit_unit<E: Error>(self) -> Result<Self::Value, E> {
                Ok(None)
            }

            fn visit_none<E: Error>(self) -> Result<Self::Value, E> {
                Ok(None)
            }

            fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
            where
                D: Deserializer<'de>,
            {
                T::deserialize(deserializer).map(Some)
            }
        }

        let visitor = BytesVisitor { out: PhantomData };
        deserializer.deserialize_option(visitor)
    }
}
<|endoftext|>


<commit_before>//! This module provides basic generic types for a filesystem.

use std::ffi::OsString;
use std::io::{Read, Seek, Write};
use std::io::Result;
use std::path::{Path, PathBuf};

/// A builder used to create directories.
///
/// This trait replaces [`std::fs::DirBuilder`] with the exception of its `new` function. To create
/// a new `DirBuilder`, use [`GenFS::new_dirbuilder`].
///
/// [`std::fs::DirBuilder`]: https://doc.rust-lang.org/std/fs/struct.DirBuilder.html
/// [`GenFS::new_dirbuilder`]: trait.GenFS.html#tymethod.new_dirbuilder
pub trait DirBuilder {
    /// Indicates that directories should be opened recursively, creating directories if they do
    /// not exist.
    fn recursive(&mut self, recursive: bool) -> &mut Self;
    /// Creates the directory specified by `path`.
    fn create<P: AsRef<Path>>(&self, path: P) -> Result<()>;
}

/// Entries returned by the iterator returned from `read_dir`.
///
/// `DirEntry` represents an entry inside a directory on a filesystem that can be inspected to
/// learn about the entry.
pub trait DirEntry {
    /// Metadata is an associated type until traits can return `impl Trait`.
    type Metadata: Metadata;
    /// FileType is an associated type until traits can return `impl Trait`.
    type FileType: FileType;

    /// Returns the full path to the file or directory this entry represents.
    fn path(&self) -> PathBuf;
    /// Returns metadata for the file this entry represents.
    fn metadata(&self) -> Result<Self::Metadata>;
    /// Returns the file type for what this entry points at.
    fn file_type(&self) -> Result<Self::FileType>;
    /// Returns the base name of the file or directory this entry represents.
    fn file_name(&self) -> OsString;
}

/// A reference to an open file on the filesystem.
///
/// This is meant to mirror `std::fs::File`, but only provides a few important functions. Sync is
/// deliberately left out as, on most systems, it is a noop or worse yet, a lie. A proper sync, to
/// ensure data is 100% truly on disk, requires a complicated sequence that is different on most
/// systems.
pub trait File: Read + Seek + Write {
    /// Metadata is an associated type until traits can return `impl Trait`.
    type Metadata: Metadata;

    /// Queries information about the underlying file.
    fn metadata(&self) -> Result<Self::Metadata>;
}

/// Represents the type of a file.
pub trait FileType {
    /// Returns whether this file type is a directory.
    fn is_dir(&self) -> bool;
    /// Returns whether this file type is a file.
    fn is_file(&self) -> bool;
}

/// Metadata information about a file.
pub trait Metadata {
    /// Permissions is an associated type until traits can return `impl Trait`.
    type Permissions: Permissions;
    /// FileType is an associated type until traits can return `impl Trait`.
    type FileType: FileType;

    /// Returns the file type for this metadata.
    fn file_type(&self) -> Self::FileType;
    /// Returns whether this metadata is for a directory.
    fn is_dir(&self) -> bool;
    /// Returns whether this metadata is for a file.
    fn is_file(&self) -> bool;
    /// Returns the size, in bytes, of the file this metadata is for.
    fn len(&self) -> u64;
    /// Returns the permissions of the file this metadata is for.
    fn permissions(&self) -> Self::Permissions;
    /// Returns whether the file is empty. This defaults to checking `len() == 0`.
    fn is_empty(&self) -> bool {
        self.len() == 0
    }
}

/// Options and flags which can be used to configure how a file is opened.
///
/// This trait replaces [`std::fs::OpenOptions`] with the exception of its `new` function. To create
/// a new `OpenOptions`, use [`GenFS::new_openopts`].
///
/// [`std::fs::OpenOptions`]: https://doc.rust-lang.org/std/fs/struct.OpenOptions.html
/// [`GenFS::new_openopts`]: trait.GenFS.html#tymethod.new_openopts
pub trait OpenOptions {
    /// File is an associated type until traits can return `impl Trait`.
    type File: File;

    /// Indicates the file's `read` state once opened.
    fn read(&mut self, read: bool) -> &mut Self;
    /// Indicates the file's `write` state once opened.
    fn write(&mut self, write: bool) -> &mut Self;
    /// Indicates whether writes should always append to the end of the file (even if other writes
    /// occured) or from the current write position. See `std::fs::OpenOptions` for more
    /// information.
    fn append(&mut self, append: bool) -> &mut Self;
    /// Indicates whether the file should be truncated on open.
    fn truncate(&mut self, truncate: bool) -> &mut Self;
    /// Sets the option to create the file if it does not exist. `write` or `append` must be used
    /// with this option.
    fn create(&mut self, create: bool) -> &mut Self;
    /// Sets the option to exclusively create this file. If the file already exists, `open` will
    /// fail. `write` or `append` must be used with this option.
    fn create_new(&mut self, create_new: bool) -> &mut Self;
    /// Opens the file at `path`.
    fn open<P: AsRef<Path>>(&self, path: P) -> Result<Self::File>;
}

/// Representation of the various permissions on a file.
pub trait Permissions {
    /// Returns whether these permissions have readonly set.
    fn readonly(&self) -> bool;
    /// Modifies the readonly fly for these permissions.
    ///
    /// This does not modify the filesystem. To modify the filesystem, use the filesystem's
    /// [`set_permissions`] function.
    ///
    /// [`set_permissions`]: trait.GenFS.html#tymethod.set_permissions
    fn set_readonly(&mut self, readonly: bool);
}

/// The single filesystem underpinning all filesystem operations.
///
/// This trait intends to be a drop in replacement for most uses of [`std::fs`]. As with
/// [`std::fs`], all methods in this trait are cross platform. Extra platform specific
/// functionality can be found in the extension traits of `rsfs::$platform_ext`.
///
/// [`std::fs`]: https://doc.rust-lang.org/std/fs/
pub trait GenFS {
    /// DirBuilder is an associated type until traits can return `impl Trait`.
    type DirBuilder: DirBuilder;
    /// DirEntry is an associated type until traits can return `impl Trait`.
    type DirEntry: DirEntry;
    /// Metadata is an associated type until traits can return `impl Trait`.
    type Metadata: Metadata;
    /// OpenOptions is an associated type until traits can return `impl Trait`.
    type OpenOptions: OpenOptions;
    /// Permissions is an associated type until traits can return `impl Trait`.
    type Permissions: Permissions;
    /// ReadDir is an associated type until traits can return `impl Trait`.
    type ReadDir: Iterator<Item = Result<Self::DirEntry>>;

    /// Returns metadata information of the file or directory at path.
    fn metadata<P: AsRef<Path>>(&self, path: P) -> Result<Self::Metadata>;

    /// Returns an iterator over entries within a directory.
    fn read_dir<P: AsRef<Path>>(&self, path: P) -> Result<Self::ReadDir>;

    /// Removes an existing, empty directory.
    fn remove_dir<P: AsRef<Path>>(&self, path: P) -> Result<()>;

    /// Removes a directory at path after removing all of its contents.
    fn remove_dir_all<P: AsRef<Path>>(&self, path: P) -> Result<()>;

    /// Removes a file from the filesystem.
    fn remove_file<P: AsRef<Path>>(&self, path: P) -> Result<()>;

    /// Renames a file or directory at `from` to `to`, replacing `to` if it exists (and, for a
    /// directory, is empty).
    fn rename<P: AsRef<Path>, Q: AsRef<Path>>(&self, from: P, to: Q) -> Result<()>;

    /// Changes the permissions of a file or directory.
    fn set_permissions<P: AsRef<Path>>(path: P, perm: Self::Permissions) -> Result<()>;

    /// Returns a new OpenOptions for a file for this filesytem.
    ///
    /// This method replaces [`std::fs::OpenOptions::new()`], which now needs to be a part of this
    /// trait to ensure any new file belongs to the `GenFS` that created the `OpenOptions`.
    ///
    /// [`std::fs::OpenOptions::new()`]: https://doc.rust-lang.org/std/fs/struct.OpenOptions.html#method.new
    fn new_openopts(&self) -> Self::OpenOptions;

    /// Returns a new DirBuilder for a directory for this filesystem.
    ///
    /// This method replaces [`std::fs::DirBuilder::new()`], which now needs to be a part of this
    /// trait to ensure any new directory belongs to the `GenFS` that created the `DirBuilder`.
    ///
    /// [`std::fs::DirBuilder::new()`]: https://doc.rust-lang.org/std/fs/struct.DirBuilder.html#method.new
    fn new_dirbuilder(&self) -> Self::DirBuilder;
}
<commit_msg>add self to set_perms<commit_after>//! This module provides basic generic types for a filesystem.

use std::ffi::OsString;
use std::io::{Read, Seek, Write};
use std::io::Result;
use std::path::{Path, PathBuf};

/// A builder used to create directories.
///
/// This trait replaces [`std::fs::DirBuilder`] with the exception of its `new` function. To create
/// a new `DirBuilder`, use [`GenFS::new_dirbuilder`].
///
/// [`std::fs::DirBuilder`]: https://doc.rust-lang.org/std/fs/struct.DirBuilder.html
/// [`GenFS::new_dirbuilder`]: trait.GenFS.html#tymethod.new_dirbuilder
pub trait DirBuilder {
    /// Indicates that directories should be opened recursively, creating directories if they do
    /// not exist.
    fn recursive(&mut self, recursive: bool) -> &mut Self;
    /// Creates the directory specified by `path`.
    fn create<P: AsRef<Path>>(&self, path: P) -> Result<()>;
}

/// Entries returned by the iterator returned from `read_dir`.
///
/// `DirEntry` represents an entry inside a directory on a filesystem that can be inspected to
/// learn about the entry.
pub trait DirEntry {
    /// Metadata is an associated type until traits can return `impl Trait`.
    type Metadata: Metadata;
    /// FileType is an associated type until traits can return `impl Trait`.
    type FileType: FileType;

    /// Returns the full path to the file or directory this entry represents.
    fn path(&self) -> PathBuf;
    /// Returns metadata for the file this entry represents.
    fn metadata(&self) -> Result<Self::Metadata>;
    /// Returns the file type for what this entry points at.
    fn file_type(&self) -> Result<Self::FileType>;
    /// Returns the base name of the file or directory this entry represents.
    fn file_name(&self) -> OsString;
}

/// A reference to an open file on the filesystem.
///
/// This is meant to mirror `std::fs::File`, but only provides a few important functions. Sync is
/// deliberately left out as, on most systems, it is a noop or worse yet, a lie. A proper sync, to
/// ensure data is 100% truly on disk, requires a complicated sequence that is different on most
/// systems.
pub trait File: Read + Seek + Write {
    /// Metadata is an associated type until traits can return `impl Trait`.
    type Metadata: Metadata;

    /// Queries information about the underlying file.
    fn metadata(&self) -> Result<Self::Metadata>;
}

/// Represents the type of a file.
pub trait FileType {
    /// Returns whether this file type is a directory.
    fn is_dir(&self) -> bool;
    /// Returns whether this file type is a file.
    fn is_file(&self) -> bool;
}

/// Metadata information about a file.
pub trait Metadata {
    /// Permissions is an associated type until traits can return `impl Trait`.
    type Permissions: Permissions;
    /// FileType is an associated type until traits can return `impl Trait`.
    type FileType: FileType;

    /// Returns the file type for this metadata.
    fn file_type(&self) -> Self::FileType;
    /// Returns whether this metadata is for a directory.
    fn is_dir(&self) -> bool;
    /// Returns whether this metadata is for a file.
    fn is_file(&self) -> bool;
    /// Returns the size, in bytes, of the file this metadata is for.
    fn len(&self) -> u64;
    /// Returns the permissions of the file this metadata is for.
    fn permissions(&self) -> Self::Permissions;
    /// Returns whether the file is empty. This defaults to checking `len() == 0`.
    fn is_empty(&self) -> bool {
        self.len() == 0
    }
}

/// Options and flags which can be used to configure how a file is opened.
///
/// This trait replaces [`std::fs::OpenOptions`] with the exception of its `new` function. To create
/// a new `OpenOptions`, use [`GenFS::new_openopts`].
///
/// [`std::fs::OpenOptions`]: https://doc.rust-lang.org/std/fs/struct.OpenOptions.html
/// [`GenFS::new_openopts`]: trait.GenFS.html#tymethod.new_openopts
pub trait OpenOptions {
    /// File is an associated type until traits can return `impl Trait`.
    type File: File;

    /// Indicates the file's `read` state once opened.
    fn read(&mut self, read: bool) -> &mut Self;
    /// Indicates the file's `write` state once opened.
    fn write(&mut self, write: bool) -> &mut Self;
    /// Indicates whether writes should always append to the end of the file (even if other writes
    /// occured) or from the current write position. See `std::fs::OpenOptions` for more
    /// information.
    fn append(&mut self, append: bool) -> &mut Self;
    /// Indicates whether the file should be truncated on open.
    fn truncate(&mut self, truncate: bool) -> &mut Self;
    /// Sets the option to create the file if it does not exist. `write` or `append` must be used
    /// with this option.
    fn create(&mut self, create: bool) -> &mut Self;
    /// Sets the option to exclusively create this file. If the file already exists, `open` will
    /// fail. `write` or `append` must be used with this option.
    fn create_new(&mut self, create_new: bool) -> &mut Self;
    /// Opens the file at `path`.
    fn open<P: AsRef<Path>>(&self, path: P) -> Result<Self::File>;
}

/// Representation of the various permissions on a file.
pub trait Permissions {
    /// Returns whether these permissions have readonly set.
    fn readonly(&self) -> bool;
    /// Modifies the readonly fly for these permissions.
    ///
    /// This does not modify the filesystem. To modify the filesystem, use the filesystem's
    /// [`set_permissions`] function.
    ///
    /// [`set_permissions`]: trait.GenFS.html#tymethod.set_permissions
    fn set_readonly(&mut self, readonly: bool);
}

/// The single filesystem underpinning all filesystem operations.
///
/// This trait intends to be a drop in replacement for most uses of [`std::fs`]. As with
/// [`std::fs`], all methods in this trait are cross platform. Extra platform specific
/// functionality can be found in the extension traits of `rsfs::$platform_ext`.
///
/// [`std::fs`]: https://doc.rust-lang.org/std/fs/
pub trait GenFS {
    /// DirBuilder is an associated type until traits can return `impl Trait`.
    type DirBuilder: DirBuilder;
    /// DirEntry is an associated type until traits can return `impl Trait`.
    type DirEntry: DirEntry;
    /// Metadata is an associated type until traits can return `impl Trait`.
    type Metadata: Metadata;
    /// OpenOptions is an associated type until traits can return `impl Trait`.
    type OpenOptions: OpenOptions;
    /// Permissions is an associated type until traits can return `impl Trait`.
    type Permissions: Permissions;
    /// ReadDir is an associated type until traits can return `impl Trait`.
    type ReadDir: Iterator<Item = Result<Self::DirEntry>>;

    /// Returns metadata information of the file or directory at path.
    fn metadata<P: AsRef<Path>>(&self, path: P) -> Result<Self::Metadata>;

    /// Returns an iterator over entries within a directory.
    fn read_dir<P: AsRef<Path>>(&self, path: P) -> Result<Self::ReadDir>;

    /// Removes an existing, empty directory.
    fn remove_dir<P: AsRef<Path>>(&self, path: P) -> Result<()>;

    /// Removes a directory at path after removing all of its contents.
    fn remove_dir_all<P: AsRef<Path>>(&self, path: P) -> Result<()>;

    /// Removes a file from the filesystem.
    fn remove_file<P: AsRef<Path>>(&self, path: P) -> Result<()>;

    /// Renames a file or directory at `from` to `to`, replacing `to` if it exists (and, for a
    /// directory, is empty).
    fn rename<P: AsRef<Path>, Q: AsRef<Path>>(&self, from: P, to: Q) -> Result<()>;

    /// Changes the permissions of a file or directory.
    fn set_permissions<P: AsRef<Path>>(&self, path: P, perm: Self::Permissions) -> Result<()>;

    /// Returns a new OpenOptions for a file for this filesytem.
    ///
    /// This method replaces [`std::fs::OpenOptions::new()`], which now needs to be a part of this
    /// trait to ensure any new file belongs to the `GenFS` that created the `OpenOptions`.
    ///
    /// [`std::fs::OpenOptions::new()`]: https://doc.rust-lang.org/std/fs/struct.OpenOptions.html#method.new
    fn new_openopts(&self) -> Self::OpenOptions;

    /// Returns a new DirBuilder for a directory for this filesystem.
    ///
    /// This method replaces [`std::fs::DirBuilder::new()`], which now needs to be a part of this
    /// trait to ensure any new directory belongs to the `GenFS` that created the `DirBuilder`.
    ///
    /// [`std::fs::DirBuilder::new()`]: https://doc.rust-lang.org/std/fs/struct.DirBuilder.html#method.new
    fn new_dirbuilder(&self) -> Self::DirBuilder;
}
<|endoftext|>