<commit_before>use std::{iter::once, ops::RangeInclusive};

use syntax::{
    algo::replace_children,
    ast::{
        self,
        edit::{AstNodeEdit, IndentLevel},
        make,
    },
    AstNode,
    SyntaxKind::{FN, LOOP_EXPR, L_CURLY, R_CURLY, WHILE_EXPR, WHITESPACE},
    SyntaxNode,
};

use crate::{
    assist_context::{AssistContext, Assists},
    utils::invert_boolean_expression,
    AssistId, AssistKind,
};

// Assist: convert_to_guarded_return
//
// Replace a large conditional with a guarded return.
//
// ```
// fn main() {
//     $0if cond {
//         foo();
//         bar();
//     }
// }
// ```
// ->
// ```
// fn main() {
//     if !cond {
//         return;
//     }
//     foo();
//     bar();
// }
// ```
pub(crate) fn convert_to_guarded_return(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
    let if_expr: ast::IfExpr = ctx.find_node_at_offset()?;
    if if_expr.else_branch().is_some() {
        return None;
    }

    let cond = if_expr.condition()?;

    // Check if there is an IfLet that we can handle.
    let if_let_pat = match cond.pat() {
        None => None, // No IfLet, supported.
        Some(ast::Pat::TupleStructPat(pat)) if pat.fields().count() == 1 => {
            let path = pat.path()?;
            match path.qualifier() {
                None => {
                    let bound_ident = pat.fields().next().unwrap();
                    if ast::IdentPat::can_cast(bound_ident.syntax().kind()) {
                        Some((path, bound_ident))
                    } else {
                        return None;
                    }
                }
                Some(_) => return None,
            }
        }
        Some(_) => return None, // Unsupported IfLet.
    };

    let cond_expr = cond.expr()?;
    let then_block = if_expr.then_branch()?;

    let parent_block = if_expr.syntax().parent()?.ancestors().find_map(ast::BlockExpr::cast)?;

    if parent_block.tail_expr()? != if_expr.clone().into() {
        return None;
    }

    // check for early return and continue
    let first_in_then_block = then_block.syntax().first_child()?;
    if ast::ReturnExpr::can_cast(first_in_then_block.kind())
        || ast::ContinueExpr::can_cast(first_in_then_block.kind())
        || first_in_then_block
            .children()
            .any(|x| ast::ReturnExpr::can_cast(x.kind()) || ast::ContinueExpr::can_cast(x.kind()))
    {
        return None;
    }

    let parent_container = parent_block.syntax().parent()?;

    let early_expression: ast::Expr = match parent_container.kind() {
        WHILE_EXPR | LOOP_EXPR => make::expr_continue(),
        FN => make::expr_return(None),
        _ => return None,
    };

    if then_block.syntax().first_child_or_token().map(|t| t.kind() == L_CURLY).is_none() {
        return None;
    }

    then_block.syntax().last_child_or_token().filter(|t| t.kind() == R_CURLY)?;

    let target = if_expr.syntax().text_range();
    acc.add(
        AssistId("convert_to_guarded_return", AssistKind::RefactorRewrite),
        "Convert to guarded return",
        target,
        |edit| {
            let if_indent_level = IndentLevel::from_node(if_expr.syntax());
            let new_block = match if_let_pat {
                None => {
                    // If.
                    let new_expr = {
                        let then_branch =
                            make::block_expr(once(make::expr_stmt(early_expression).into()), None);
                        let cond = invert_boolean_expression(cond_expr);
                        make::expr_if(make::condition(cond, None), then_branch, None)
                            .indent(if_indent_level)
                    };
                    replace(new_expr.syntax(), &then_block, &parent_block, &if_expr)
                }
                Some((path, bound_ident)) => {
                    // If-let.
                    let match_expr = {
                        let happy_arm = {
                            let pat = make::tuple_struct_pat(
                                path,
                                once(make::ext::simple_ident_pat(make::name("it")).into()),
                            );
                            let expr = {
                                let path = make::ext::ident_path("it");
                                make::expr_path(path)
                            };
                            make::match_arm(once(pat.into()), None, expr)
                        };

                        let sad_arm = make::match_arm(
                            // FIXME: would be cool to use `None` or `Err(_)` if appropriate
                            once(make::wildcard_pat().into()),
                            None,
                            early_expression,
                        );

                        make::expr_match(cond_expr, make::match_arm_list(vec![happy_arm, sad_arm]))
                    };

                    let let_stmt = make::let_stmt(bound_ident, None, Some(match_expr));
                    let let_stmt = let_stmt.indent(if_indent_level);
                    replace(let_stmt.syntax(), &then_block, &parent_block, &if_expr)
                }
            };
            edit.replace_ast(parent_block, ast::BlockExpr::cast(new_block).unwrap());

            fn replace(
                new_expr: &SyntaxNode,
                then_block: &ast::BlockExpr,
                parent_block: &ast::BlockExpr,
                if_expr: &ast::IfExpr,
            ) -> SyntaxNode {
                let then_block_items = then_block.dedent(IndentLevel(1));
                let end_of_then = then_block_items.syntax().last_child_or_token().unwrap();
                let end_of_then =
                    if end_of_then.prev_sibling_or_token().map(|n| n.kind()) == Some(WHITESPACE) {
                        end_of_then.prev_sibling_or_token().unwrap()
                    } else {
                        end_of_then
                    };
                let mut then_statements = new_expr.children_with_tokens().chain(
                    then_block_items
                        .syntax()
                        .children_with_tokens()
                        .skip(1)
                        .take_while(|i| *i != end_of_then),
                );
                replace_children(
                    parent_block.syntax(),
                    RangeInclusive::new(
                        if_expr.clone().syntax().clone().into(),
                        if_expr.syntax().clone().into(),
                    ),
                    &mut then_statements,
                )
            }
        },
    )
}

#[cfg(test)]
mod tests {
    use crate::tests::{check_assist, check_assist_not_applicable};

    use super::*;

    #[test]
    fn convert_inside_fn() {
        check_assist(
            convert_to_guarded_return,
            r#"
            fn main() {
                bar();
                if$0 true {
                    foo();

                    // comment
                    bar();
                }
            }
            "#,
            r#"
            fn main() {
                bar();
                if false {
                    return;
                }
                foo();

                // comment
                bar();
            }
            "#,
        );
    }

    #[test]
    fn convert_let_inside_fn() {
        check_assist(
            convert_to_guarded_return,
            r#"
            fn main(n: Option<String>) {
                bar();
                if$0 let Some(n) = n {
                    foo(n);

                    // comment
                    bar();
                }
            }
            "#,
            r#"
            fn main(n: Option<String>) {
                bar();
                let n = match n {
                    Some(it) => it,
                    _ => return,
                };
                foo(n);

                // comment
                bar();
            }
            "#,
        );
    }

    #[test]
    fn convert_if_let_result() {
        check_assist(
            convert_to_guarded_return,
            r#"
            fn main() {
                if$0 let Ok(x) = Err(92) {
                    foo(x);
                }
            }
            "#,
            r#"
            fn main() {
                let x = match Err(92) {
                    Ok(it) => it,
                    _ => return,
                };
                foo(x);
            }
            "#,
        );
    }

    #[test]
    fn convert_let_ok_inside_fn() {
        check_assist(
            convert_to_guarded_return,
            r#"
            fn main(n: Option<String>) {
                bar();
                if$0 let Some(n) = n {
                    foo(n);

                    // comment
                    bar();
                }
            }
            "#,
            r#"
            fn main(n: Option<String>) {
                bar();
                let n = match n {
                    Some(it) => it,
                    _ => return,
                };
                foo(n);

                // comment
                bar();
            }
            "#,
        );
    }

    #[test]
    fn convert_let_mut_ok_inside_fn() {
        check_assist(
            convert_to_guarded_return,
            r#"
            fn main(n: Option<String>) {
                bar();
                if$0 let Some(mut n) = n {
                    foo(n);

                    // comment
                    bar();
                }
            }
            "#,
            r#"
            fn main(n: Option<String>) {
                bar();
                let mut n = match n {
                    Some(it) => it,
                    _ => return,
                };
                foo(n);

                // comment
                bar();
            }
            "#,
        );
    }

    #[test]
    fn convert_let_ref_ok_inside_fn() {
        check_assist(
            convert_to_guarded_return,
            r#"
            fn main(n: Option<&str>) {
                bar();
                if$0 let Some(ref n) = n {
                    foo(n);

                    // comment
                    bar();
                }
            }
            "#,
            r#"
            fn main(n: Option<&str>) {
                bar();
                let ref n = match n {
                    Some(it) => it,
                    _ => return,
                };
                foo(n);

                // comment
                bar();
            }
            "#,
        );
    }

    #[test]
    fn convert_inside_while() {
        check_assist(
            convert_to_guarded_return,
            r#"
            fn main() {
                while true {
                    if$0 true {
                        foo();
                        bar();
                    }
                }
            }
            "#,
            r#"
            fn main() {
                while true {
                    if false {
                        continue;
                    }
                    foo();
                    bar();
                }
            }
            "#,
        );
    }

    #[test]
    fn convert_let_inside_while() {
        check_assist(
            convert_to_guarded_return,
            r#"
            fn main() {
                while true {
                    if$0 let Some(n) = n {
                        foo(n);
                        bar();
                    }
                }
            }
            "#,
            r#"
            fn main() {
                while true {
                    let n = match n {
                        Some(it) => it,
                        _ => continue,
                    };
                    foo(n);
                    bar();
                }
            }
            "#,
        );
    }

    #[test]
    fn convert_inside_loop() {
        check_assist(
            convert_to_guarded_return,
            r#"
            fn main() {
                loop {
                    if$0 true {
                        foo();
                        bar();
                    }
                }
            }
            "#,
            r#"
            fn main() {
                loop {
                    if false {
                        continue;
                    }
                    foo();
                    bar();
                }
            }
            "#,
        );
    }

    #[test]
    fn convert_let_inside_loop() {
        check_assist(
            convert_to_guarded_return,
            r#"
            fn main() {
                loop {
                    if$0 let Some(n) = n {
                        foo(n);
                        bar();
                    }
                }
            }
            "#,
            r#"
            fn main() {
                loop {
                    let n = match n {
                        Some(it) => it,
                        _ => continue,
                    };
                    foo(n);
                    bar();
                }
            }
            "#,
        );
    }

    #[test]
    fn ignore_already_converted_if() {
        check_assist_not_applicable(
            convert_to_guarded_return,
            r#"
            fn main() {
                if$0 true {
                    return;
                }
            }
            "#,
        );
    }

    #[test]
    fn ignore_already_converted_loop() {
        check_assist_not_applicable(
            convert_to_guarded_return,
            r#"
            fn main() {
                loop {
                    if$0 true {
                        continue;
                    }
                }
            }
            "#,
        );
    }

    #[test]
    fn ignore_return() {
        check_assist_not_applicable(
            convert_to_guarded_return,
            r#"
            fn main() {
                if$0 true {
                    return
                }
            }
            "#,
        );
    }

    #[test]
    fn ignore_else_branch() {
        check_assist_not_applicable(
            convert_to_guarded_return,
            r#"
            fn main() {
                if$0 true {
                    foo();
                } else {
                    bar()
                }
            }
            "#,
        );
    }

    #[test]
    fn ignore_statements_aftert_if() {
        check_assist_not_applicable(
            convert_to_guarded_return,
            r#"
            fn main() {
                if$0 true {
                    foo();
                }
                bar();
            }
            "#,
        );
    }

    #[test]
    fn ignore_statements_inside_if() {
        check_assist_not_applicable(
            convert_to_guarded_return,
            r#"
            fn main() {
                if false {
                    if$0 true {
                        foo();
                    }
                }
            }
            "#,
        );
    }
}
<commit_msg>internal: use standard test style<commit_after>use std::{iter::once, ops::RangeInclusive};

use syntax::{
    algo::replace_children,
    ast::{
        self,
        edit::{AstNodeEdit, IndentLevel},
        make,
    },
    AstNode,
    SyntaxKind::{FN, LOOP_EXPR, L_CURLY, R_CURLY, WHILE_EXPR, WHITESPACE},
    SyntaxNode,
};

use crate::{
    assist_context::{AssistContext, Assists},
    utils::invert_boolean_expression,
    AssistId, AssistKind,
};

// Assist: convert_to_guarded_return
//
// Replace a large conditional with a guarded return.
//
// ```
// fn main() {
//     $0if cond {
//         foo();
//         bar();
//     }
// }
// ```
// ->
// ```
// fn main() {
//     if !cond {
//         return;
//     }
//     foo();
//     bar();
// }
// ```
pub(crate) fn convert_to_guarded_return(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
    let if_expr: ast::IfExpr = ctx.find_node_at_offset()?;
    if if_expr.else_branch().is_some() {
        return None;
    }

    let cond = if_expr.condition()?;

    // Check if there is an IfLet that we can handle.
    let if_let_pat = match cond.pat() {
        None => None, // No IfLet, supported.
        Some(ast::Pat::TupleStructPat(pat)) if pat.fields().count() == 1 => {
            let path = pat.path()?;
            match path.qualifier() {
                None => {
                    let bound_ident = pat.fields().next().unwrap();
                    if ast::IdentPat::can_cast(bound_ident.syntax().kind()) {
                        Some((path, bound_ident))
                    } else {
                        return None;
                    }
                }
                Some(_) => return None,
            }
        }
        Some(_) => return None, // Unsupported IfLet.
    };

    let cond_expr = cond.expr()?;
    let then_block = if_expr.then_branch()?;

    let parent_block = if_expr.syntax().parent()?.ancestors().find_map(ast::BlockExpr::cast)?;

    if parent_block.tail_expr()? != if_expr.clone().into() {
        return None;
    }

    // check for early return and continue
    let first_in_then_block = then_block.syntax().first_child()?;
    if ast::ReturnExpr::can_cast(first_in_then_block.kind())
        || ast::ContinueExpr::can_cast(first_in_then_block.kind())
        || first_in_then_block
            .children()
            .any(|x| ast::ReturnExpr::can_cast(x.kind()) || ast::ContinueExpr::can_cast(x.kind()))
    {
        return None;
    }

    let parent_container = parent_block.syntax().parent()?;

    let early_expression: ast::Expr = match parent_container.kind() {
        WHILE_EXPR | LOOP_EXPR => make::expr_continue(),
        FN => make::expr_return(None),
        _ => return None,
    };

    if then_block.syntax().first_child_or_token().map(|t| t.kind() == L_CURLY).is_none() {
        return None;
    }

    then_block.syntax().last_child_or_token().filter(|t| t.kind() == R_CURLY)?;

    let target = if_expr.syntax().text_range();
    acc.add(
        AssistId("convert_to_guarded_return", AssistKind::RefactorRewrite),
        "Convert to guarded return",
        target,
        |edit| {
            let if_indent_level = IndentLevel::from_node(if_expr.syntax());
            let new_block = match if_let_pat {
                None => {
                    // If.
                    let new_expr = {
                        let then_branch =
                            make::block_expr(once(make::expr_stmt(early_expression).into()), None);
                        let cond = invert_boolean_expression(cond_expr);
                        make::expr_if(make::condition(cond, None), then_branch, None)
                            .indent(if_indent_level)
                    };
                    replace(new_expr.syntax(), &then_block, &parent_block, &if_expr)
                }
                Some((path, bound_ident)) => {
                    // If-let.
                    let match_expr = {
                        let happy_arm = {
                            let pat = make::tuple_struct_pat(
                                path,
                                once(make::ext::simple_ident_pat(make::name("it")).into()),
                            );
                            let expr = {
                                let path = make::ext::ident_path("it");
                                make::expr_path(path)
                            };
                            make::match_arm(once(pat.into()), None, expr)
                        };

                        let sad_arm = make::match_arm(
                            // FIXME: would be cool to use `None` or `Err(_)` if appropriate
                            once(make::wildcard_pat().into()),
                            None,
                            early_expression,
                        );

                        make::expr_match(cond_expr, make::match_arm_list(vec![happy_arm, sad_arm]))
                    };

                    let let_stmt = make::let_stmt(bound_ident, None, Some(match_expr));
                    let let_stmt = let_stmt.indent(if_indent_level);
                    replace(let_stmt.syntax(), &then_block, &parent_block, &if_expr)
                }
            };
            edit.replace_ast(parent_block, ast::BlockExpr::cast(new_block).unwrap());

            fn replace(
                new_expr: &SyntaxNode,
                then_block: &ast::BlockExpr,
                parent_block: &ast::BlockExpr,
                if_expr: &ast::IfExpr,
            ) -> SyntaxNode {
                let then_block_items = then_block.dedent(IndentLevel(1));
                let end_of_then = then_block_items.syntax().last_child_or_token().unwrap();
                let end_of_then =
                    if end_of_then.prev_sibling_or_token().map(|n| n.kind()) == Some(WHITESPACE) {
                        end_of_then.prev_sibling_or_token().unwrap()
                    } else {
                        end_of_then
                    };
                let mut then_statements = new_expr.children_with_tokens().chain(
                    then_block_items
                        .syntax()
                        .children_with_tokens()
                        .skip(1)
                        .take_while(|i| *i != end_of_then),
                );
                replace_children(
                    parent_block.syntax(),
                    RangeInclusive::new(
                        if_expr.clone().syntax().clone().into(),
                        if_expr.syntax().clone().into(),
                    ),
                    &mut then_statements,
                )
            }
        },
    )
}

#[cfg(test)]
mod tests {
    use crate::tests::{check_assist, check_assist_not_applicable};

    use super::*;

    #[test]
    fn convert_inside_fn() {
        check_assist(
            convert_to_guarded_return,
            r#"
fn main() {
    bar();
    if$0 true {
        foo();

        // comment
        bar();
    }
}
"#,
            r#"
fn main() {
    bar();
    if false {
        return;
    }
    foo();

    // comment
    bar();
}
"#,
        );
    }

    #[test]
    fn convert_let_inside_fn() {
        check_assist(
            convert_to_guarded_return,
            r#"
fn main(n: Option<String>) {
    bar();
    if$0 let Some(n) = n {
        foo(n);

        // comment
        bar();
    }
}
"#,
            r#"
fn main(n: Option<String>) {
    bar();
    let n = match n {
        Some(it) => it,
        _ => return,
    };
    foo(n);

    // comment
    bar();
}
"#,
        );
    }

    #[test]
    fn convert_if_let_result() {
        check_assist(
            convert_to_guarded_return,
            r#"
fn main() {
    if$0 let Ok(x) = Err(92) {
        foo(x);
    }
}
"#,
            r#"
fn main() {
    let x = match Err(92) {
        Ok(it) => it,
        _ => return,
    };
    foo(x);
}
"#,
        );
    }

    #[test]
    fn convert_let_ok_inside_fn() {
        check_assist(
            convert_to_guarded_return,
            r#"
fn main(n: Option<String>) {
    bar();
    if$0 let Some(n) = n {
        foo(n);

        // comment
        bar();
    }
}
"#,
            r#"
fn main(n: Option<String>) {
    bar();
    let n = match n {
        Some(it) => it,
        _ => return,
    };
    foo(n);

    // comment
    bar();
}
"#,
        );
    }

    #[test]
    fn convert_let_mut_ok_inside_fn() {
        check_assist(
            convert_to_guarded_return,
            r#"
fn main(n: Option<String>) {
    bar();
    if$0 let Some(mut n) = n {
        foo(n);

        // comment
        bar();
    }
}
"#,
            r#"
fn main(n: Option<String>) {
    bar();
    let mut n = match n {
        Some(it) => it,
        _ => return,
    };
    foo(n);

    // comment
    bar();
}
"#,
        );
    }

    #[test]
    fn convert_let_ref_ok_inside_fn() {
        check_assist(
            convert_to_guarded_return,
            r#"
fn main(n: Option<&str>) {
    bar();
    if$0 let Some(ref n) = n {
        foo(n);

        // comment
        bar();
    }
}
"#,
            r#"
fn main(n: Option<&str>) {
    bar();
    let ref n = match n {
        Some(it) => it,
        _ => return,
    };
    foo(n);

    // comment
    bar();
}
"#,
        );
    }

    #[test]
    fn convert_inside_while() {
        check_assist(
            convert_to_guarded_return,
            r#"
fn main() {
    while true {
        if$0 true {
            foo();
            bar();
        }
    }
}
"#,
            r#"
fn main() {
    while true {
        if false {
            continue;
        }
        foo();
        bar();
    }
}
"#,
        );
    }

    #[test]
    fn convert_let_inside_while() {
        check_assist(
            convert_to_guarded_return,
            r#"
fn main() {
    while true {
        if$0 let Some(n) = n {
            foo(n);
            bar();
        }
    }
}
"#,
            r#"
fn main() {
    while true {
        let n = match n {
            Some(it) => it,
            _ => continue,
        };
        foo(n);
        bar();
    }
}
"#,
        );
    }

    #[test]
    fn convert_inside_loop() {
        check_assist(
            convert_to_guarded_return,
            r#"
fn main() {
    loop {
        if$0 true {
            foo();
            bar();
        }
    }
}
"#,
            r#"
fn main() {
    loop {
        if false {
            continue;
        }
        foo();
        bar();
    }
}
"#,
        );
    }

    #[test]
    fn convert_let_inside_loop() {
        check_assist(
            convert_to_guarded_return,
            r#"
fn main() {
    loop {
        if$0 let Some(n) = n {
            foo(n);
            bar();
        }
    }
}
"#,
            r#"
fn main() {
    loop {
        let n = match n {
            Some(it) => it,
            _ => continue,
        };
        foo(n);
        bar();
    }
}
"#,
        );
    }

    #[test]
    fn ignore_already_converted_if() {
        check_assist_not_applicable(
            convert_to_guarded_return,
            r#"
fn main() {
    if$0 true {
        return;
    }
}
"#,
        );
    }

    #[test]
    fn ignore_already_converted_loop() {
        check_assist_not_applicable(
            convert_to_guarded_return,
            r#"
fn main() {
    loop {
        if$0 true {
            continue;
        }
    }
}
"#,
        );
    }

    #[test]
    fn ignore_return() {
        check_assist_not_applicable(
            convert_to_guarded_return,
            r#"
fn main() {
    if$0 true {
        return
    }
}
"#,
        );
    }

    #[test]
    fn ignore_else_branch() {
        check_assist_not_applicable(
            convert_to_guarded_return,
            r#"
fn main() {
    if$0 true {
        foo();
    } else {
        bar()
    }
}
"#,
        );
    }

    #[test]
    fn ignore_statements_aftert_if() {
        check_assist_not_applicable(
            convert_to_guarded_return,
            r#"
fn main() {
    if$0 true {
        foo();
    }
    bar();
}
"#,
        );
    }

    #[test]
    fn ignore_statements_inside_if() {
        check_assist_not_applicable(
            convert_to_guarded_return,
            r#"
fn main() {
    if false {
        if$0 true {
            foo();
        }
    }
}
"#,
        );
    }
}
<|endoftext|>


<commit_before>use clap::AppSettings;
use roff::{bold, italic, roman, Inline, Roff};

pub(crate) fn subcommand_heading(cmd: &clap::Command) -> String {
    match cmd.get_subcommand_help_heading() {
        Some(title) => title.to_string(),
        None => "SUBCOMMANDS".to_string(),
    }
}

pub(crate) fn about(roff: &mut Roff, cmd: &clap::Command) {
    let s = match cmd.get_about().or_else(|| cmd.get_long_about()) {
        Some(about) => format!("{} - {}", cmd.get_name(), about),
        None => cmd.get_name().to_string(),
    };
    roff.text([roman(&s)]);
}

pub(crate) fn description(roff: &mut Roff, cmd: &clap::Command) {
    if let Some(about) = cmd.get_long_about().or_else(|| cmd.get_about()) {
        for line in about.lines() {
            if line.trim().is_empty() {
                roff.control("PP", []);
            } else {
                roff.text([roman(line)]);
            }
        }
    }
}

pub(crate) fn synopsis(roff: &mut Roff, cmd: &clap::Command) {
    let mut line = vec![bold(cmd.get_name()), roman(" ")];

    for opt in cmd.get_arguments() {
        let (lhs, rhs) = option_markers(opt);
        match (opt.get_short(), opt.get_long()) {
            (Some(short), Some(long)) => {
                line.push(roman(lhs));
                line.push(bold(&format!("-{}", short)));
                line.push(roman("|"));
                line.push(bold(&format!("--{}", long)));
                line.push(roman(rhs));
                line.push(roman(" "));
            }
            (Some(short), None) => {
                line.push(roman(lhs));
                line.push(bold(&format!("-{} ", short)));
                line.push(roman(rhs));
                line.push(roman(" "));
            }
            (None, Some(long)) => {
                line.push(roman(lhs));
                line.push(bold(&format!("--{}", long)));
                line.push(roman(rhs));
                line.push(roman(" "));
            }
            (None, None) => (),
        };
    }

    for arg in cmd.get_positionals() {
        let (lhs, rhs) = option_markers(arg);
        line.push(roman(lhs));
        line.push(italic(arg.get_id()));
        line.push(roman(rhs));
        line.push(roman(" "));
    }

    if cmd.has_subcommands() {
        let (lhs, rhs) = subcommand_markers(cmd);
        line.push(roman(lhs));
        line.push(italic(
            &cmd.get_subcommand_value_name()
                .unwrap_or(&subcommand_heading(cmd))
                .to_lowercase(),
        ));
        line.push(roman(rhs));
    }

    roff.text(line);
}

pub(crate) fn options(roff: &mut Roff, cmd: &clap::Command) {
    let items: Vec<_> = cmd.get_arguments().filter(|i| !i.is_hide_set()).collect();

    for opt in items.iter().filter(|a| !a.is_positional()) {
        let mut body = vec![];

        let mut header = match (opt.get_short(), opt.get_long()) {
            (Some(short), Some(long)) => {
                vec![short_option(short), roman(", "), long_option(long)]
            }
            (Some(short), None) => vec![short_option(short)],
            (None, Some(long)) => vec![long_option(long)],
            (None, None) => vec![],
        };

        if let Some(value) = &opt.get_value_names() {
            header.push(roman("="));
            header.push(italic(&value.join(" ")));
        }

        if let Some(defs) = option_default_values(opt) {
            header.push(roman(" "));
            header.push(roman(&defs));
        }

        if let Some(help) = opt.get_long_help().or_else(|| opt.get_help()) {
            body.push(roman(help));
        }

        if let Some(mut env) = option_environment(opt) {
            body.append(&mut env);
        }

        roff.control("TP", []);
        roff.text(header);
        roff.text(body);
    }

    for pos in items.iter().filter(|a| a.is_positional()) {
        let (lhs, rhs) = option_markers(pos);
        let name = format!("{}{}{}", lhs, pos.get_id(), rhs);

        let mut header = vec![bold(&name)];

        let mut body = vec![];

        if let Some(defs) = option_default_values(pos) {
            header.push(roman(&format!(" {}", defs)));
        }

        if let Some(help) = pos.get_long_help().or_else(|| pos.get_help()) {
            body.push(roman(&help.to_string()));
        }

        if let Some(mut env) = option_environment(pos) {
            body.append(&mut env);
        }

        roff.control("TP", []);
        roff.text(body);
    }
}

pub(crate) fn subcommands(roff: &mut Roff, cmd: &clap::Command, section: &str) {
    for sub in cmd.get_subcommands().filter(|s| !s.is_hide_set()) {
        roff.control("TP", []);

        let name = format!("{}-{}({})", cmd.get_name(), sub.get_name(), section);
        roff.text([roman(&name)]);

        if let Some(about) = sub.get_about().or_else(|| sub.get_long_about()) {
            for line in about.lines() {
                roff.text([roman(line)]);
            }
        }
    }
}

pub(crate) fn version(cmd: &clap::Command) -> String {
    format!(
        "v{}",
        cmd.get_long_version()
            .or_else(|| cmd.get_version())
            .unwrap()
    )
}

pub(crate) fn after_help(roff: &mut Roff, cmd: &clap::Command) {
    if let Some(about) = cmd.get_after_long_help().or_else(|| cmd.get_after_help()) {
        for line in about.lines() {
            roff.text([roman(line)]);
        }
    }
}

fn subcommand_markers(cmd: &clap::Command) -> (&'static str, &'static str) {
    #[allow(deprecated)]
    markers(cmd.is_subcommand_required_set() || cmd.is_set(AppSettings::SubcommandRequiredElseHelp))
}

fn option_markers(opt: &clap::Arg) -> (&'static str, &'static str) {
    markers(opt.is_required_set())
}

fn markers(required: bool) -> (&'static str, &'static str) {
    if required {
        ("<", ">")
    } else {
        ("[", "]")
    }
}

fn short_option(opt: char) -> Inline {
    bold(&format!("-{}", opt))
}

fn long_option(opt: &str) -> Inline {
    bold(&format!("--{}", opt))
}

fn option_environment(opt: &clap::Arg) -> Option<Vec<Inline>> {
    if opt.is_hide_env_set() {
        return None;
    } else if let Some(env) = opt.get_env() {
        return Some(vec![
            roman("May also be specified with the "),
            bold(env.to_string_lossy().to_owned()),
            roman(" environment variable. "),
        ]);
    }

    None
}

fn option_default_values(opt: &clap::Arg) -> Option<String> {
    if !opt.get_default_values().is_empty() {
        let values = opt
            .get_default_values()
            .iter()
            .map(|s| s.to_string_lossy())
            .collect::<Vec<_>>()
            .join(",");

        return Some(format!("[default: {}]", values));
    }

    None
}
<commit_msg>fix(clap_mangen): Hide hidden flags in synopsis<commit_after>use clap::AppSettings;
use roff::{bold, italic, roman, Inline, Roff};

pub(crate) fn subcommand_heading(cmd: &clap::Command) -> String {
    match cmd.get_subcommand_help_heading() {
        Some(title) => title.to_string(),
        None => "SUBCOMMANDS".to_string(),
    }
}

pub(crate) fn about(roff: &mut Roff, cmd: &clap::Command) {
    let s = match cmd.get_about().or_else(|| cmd.get_long_about()) {
        Some(about) => format!("{} - {}", cmd.get_name(), about),
        None => cmd.get_name().to_string(),
    };
    roff.text([roman(&s)]);
}

pub(crate) fn description(roff: &mut Roff, cmd: &clap::Command) {
    if let Some(about) = cmd.get_long_about().or_else(|| cmd.get_about()) {
        for line in about.lines() {
            if line.trim().is_empty() {
                roff.control("PP", []);
            } else {
                roff.text([roman(line)]);
            }
        }
    }
}

pub(crate) fn synopsis(roff: &mut Roff, cmd: &clap::Command) {
    let mut line = vec![bold(cmd.get_name()), roman(" ")];

    for opt in cmd.get_arguments().filter(|i| !i.is_hide_set()) {
        let (lhs, rhs) = option_markers(opt);
        match (opt.get_short(), opt.get_long()) {
            (Some(short), Some(long)) => {
                line.push(roman(lhs));
                line.push(bold(&format!("-{}", short)));
                line.push(roman("|"));
                line.push(bold(&format!("--{}", long)));
                line.push(roman(rhs));
                line.push(roman(" "));
            }
            (Some(short), None) => {
                line.push(roman(lhs));
                line.push(bold(&format!("-{} ", short)));
                line.push(roman(rhs));
                line.push(roman(" "));
            }
            (None, Some(long)) => {
                line.push(roman(lhs));
                line.push(bold(&format!("--{}", long)));
                line.push(roman(rhs));
                line.push(roman(" "));
            }
            (None, None) => (),
        };
    }

    for arg in cmd.get_positionals() {
        let (lhs, rhs) = option_markers(arg);
        line.push(roman(lhs));
        line.push(italic(arg.get_id()));
        line.push(roman(rhs));
        line.push(roman(" "));
    }

    if cmd.has_subcommands() {
        let (lhs, rhs) = subcommand_markers(cmd);
        line.push(roman(lhs));
        line.push(italic(
            &cmd.get_subcommand_value_name()
                .unwrap_or(&subcommand_heading(cmd))
                .to_lowercase(),
        ));
        line.push(roman(rhs));
    }

    roff.text(line);
}

pub(crate) fn options(roff: &mut Roff, cmd: &clap::Command) {
    let items: Vec<_> = cmd.get_arguments().filter(|i| !i.is_hide_set()).collect();

    for opt in items.iter().filter(|a| !a.is_positional()) {
        let mut body = vec![];

        let mut header = match (opt.get_short(), opt.get_long()) {
            (Some(short), Some(long)) => {
                vec![short_option(short), roman(", "), long_option(long)]
            }
            (Some(short), None) => vec![short_option(short)],
            (None, Some(long)) => vec![long_option(long)],
            (None, None) => vec![],
        };

        if let Some(value) = &opt.get_value_names() {
            header.push(roman("="));
            header.push(italic(&value.join(" ")));
        }

        if let Some(defs) = option_default_values(opt) {
            header.push(roman(" "));
            header.push(roman(&defs));
        }

        if let Some(help) = opt.get_long_help().or_else(|| opt.get_help()) {
            body.push(roman(help));
        }

        if let Some(mut env) = option_environment(opt) {
            body.append(&mut env);
        }

        roff.control("TP", []);
        roff.text(header);
        roff.text(body);
    }

    for pos in items.iter().filter(|a| a.is_positional()) {
        let (lhs, rhs) = option_markers(pos);
        let name = format!("{}{}{}", lhs, pos.get_id(), rhs);

        let mut header = vec![bold(&name)];

        let mut body = vec![];

        if let Some(defs) = option_default_values(pos) {
            header.push(roman(&format!(" {}", defs)));
        }

        if let Some(help) = pos.get_long_help().or_else(|| pos.get_help()) {
            body.push(roman(&help.to_string()));
        }

        if let Some(mut env) = option_environment(pos) {
            body.append(&mut env);
        }

        roff.control("TP", []);
        roff.text(body);
    }
}

pub(crate) fn subcommands(roff: &mut Roff, cmd: &clap::Command, section: &str) {
    for sub in cmd.get_subcommands().filter(|s| !s.is_hide_set()) {
        roff.control("TP", []);

        let name = format!("{}-{}({})", cmd.get_name(), sub.get_name(), section);
        roff.text([roman(&name)]);

        if let Some(about) = sub.get_about().or_else(|| sub.get_long_about()) {
            for line in about.lines() {
                roff.text([roman(line)]);
            }
        }
    }
}

pub(crate) fn version(cmd: &clap::Command) -> String {
    format!(
        "v{}",
        cmd.get_long_version()
            .or_else(|| cmd.get_version())
            .unwrap()
    )
}

pub(crate) fn after_help(roff: &mut Roff, cmd: &clap::Command) {
    if let Some(about) = cmd.get_after_long_help().or_else(|| cmd.get_after_help()) {
        for line in about.lines() {
            roff.text([roman(line)]);
        }
    }
}

fn subcommand_markers(cmd: &clap::Command) -> (&'static str, &'static str) {
    #[allow(deprecated)]
    markers(cmd.is_subcommand_required_set() || cmd.is_set(AppSettings::SubcommandRequiredElseHelp))
}

fn option_markers(opt: &clap::Arg) -> (&'static str, &'static str) {
    markers(opt.is_required_set())
}

fn markers(required: bool) -> (&'static str, &'static str) {
    if required {
        ("<", ">")
    } else {
        ("[", "]")
    }
}

fn short_option(opt: char) -> Inline {
    bold(&format!("-{}", opt))
}

fn long_option(opt: &str) -> Inline {
    bold(&format!("--{}", opt))
}

fn option_environment(opt: &clap::Arg) -> Option<Vec<Inline>> {
    if opt.is_hide_env_set() {
        return None;
    } else if let Some(env) = opt.get_env() {
        return Some(vec![
            roman("May also be specified with the "),
            bold(env.to_string_lossy().to_owned()),
            roman(" environment variable. "),
        ]);
    }

    None
}

fn option_default_values(opt: &clap::Arg) -> Option<String> {
    if !opt.get_default_values().is_empty() {
        let values = opt
            .get_default_values()
            .iter()
            .map(|s| s.to_string_lossy())
            .collect::<Vec<_>>()
            .join(",");

        return Some(format!("[default: {}]", values));
    }

    None
}
<|endoftext|>


<commit_before>mod common;
use mio_serial::SerialPortBuilderExt;

#[test]
fn test_builder_open_async() {
    let fixture = common::setup_virtual_serial_ports();
    let baud_rate = 9600;
    let builder = mio_serial::new(fixture.port_a, baud_rate);

    let stream = builder
        .open_native_async()
        .expect("unable to open serial port");

    common::assert_baud_rate(&stream, baud_rate)
}

#[test]
fn test_native_from_blocking() {
    use std::convert::TryFrom;
    let baud_rate = 9600;

    let fixture = common::setup_virtual_serial_ports();
    let port = fixture.port_a;
    let native_blocking = mio_serial::new(port, baud_rate)
        .open_native()
        .expect(format!("unable to open serial port {}", port).as_str());

    let stream = mio_serial::SerialStream::try_from(native_blocking)
        .expect("unable to convert from blocking serial port object");

    common::assert_baud_rate(&stream, baud_rate)
}

#[test]
fn test_stream_open() {
    let baud_rate = 9600;
    let fixture = common::setup_virtual_serial_ports();
    let port = fixture.port_a;
    let builder = mio_serial::new(port, baud_rate);
    let stream = mio_serial::SerialStream::open(&builder).expect("unable to open serial port");

    common::assert_baud_rate(&stream, baud_rate)
}

/// Port enumeration doesn't seem to work on virtual serial ports created by com0com during
/// the CI process
#[test]
#[ignore = "Port enumeration test does not seem to work with com0com virtual ports"]
fn test_port_enumeration() {
    let fixture = common::setup_virtual_serial_ports();
    let ports = mio_serial::available_ports().expect("unable to enumerate serial ports");
    for name in [fixture.port_a, fixture.port_b].iter() {
        ports.iter().find(|&info| info.port_name == *name).expect(
            format!(
                "unable to find serial port named {} in enumerated ports",
                name
            )
            .as_str(),
        );
    }
}

#[test]
fn test_read_write_pair() {
    let baud_rate = 38400;

    use mio::{Interest, Token};
    use std::io::{Read, Write};

    const DATA1: &[u8] = b"Here is an example string";
    const DATA2: &[u8] = b"And here is a reply to the example string";
    //const DATA1_LEN: usize = DATA1.len();
    const DEFAULT_BUF_SIZE: usize = 64;
    const TOKEN1: Token = Token(0);
    const TOKEN2: Token = Token(1);

    let fixture = common::setup_virtual_serial_ports();
    let (port_a, port_b) = (fixture.port_a, fixture.port_b);
    let (mut poll, mut events) = common::init_with_poll();

    let mut port_1 = mio_serial::new(port_a, baud_rate)
        .open_native_async()
        .expect(format!("unable to open serial port {}", port_a).as_str());
    let mut port_2 = mio_serial::new(port_b, baud_rate)
        .open_native_async()
        .expect(format!("unable to open serial port {}", port_b).as_str());

    // register both serial ports for read and write events
    poll.registry()
        .register(&mut port_1, TOKEN1, Interest::WRITABLE | Interest::READABLE)
        .expect(
            format!(
                "unable to register port {} as readable and writable",
                port_a
            )
            .as_str(),
        );
    poll.registry()
        .register(&mut port_2, TOKEN2, Interest::READABLE | Interest::WRITABLE)
        .expect(
            format!(
                "unable to register port {} as readable and writable",
                port_b
            )
            .as_str(),
        );

    let mut buf = [0u8; DEFAULT_BUF_SIZE];

    // port1 should immediately be writable
    common::expect_events(
        &mut poll,
        &mut events,
        vec![common::ExpectEvent::new(TOKEN1, Interest::WRITABLE)],
    );

    // port2 should be blocking
    common::assert_would_block(port_2.read(&mut buf).into());

    // write data on port 1
    common::checked_write(&mut port_1, DATA1);
    port_1
        .flush()
        .expect(format!("unable to flush serial port {}", port_a).as_str());

    // port 2 should now be readable
    common::expect_events(
        &mut poll,
        &mut events,
        vec![common::ExpectEvent::new(TOKEN2, Interest::READABLE)],
    );

    // read data on port 2
    common::checked_read(&mut port_2, &mut buf, DATA1);

    // port 2 should then return to blocking
    common::assert_would_block(port_2.read(&mut buf));

    // port 1 should be blocking on read for the reply
    common::assert_would_block(port_1.read(&mut buf));

    // send data back on port 2
    common::checked_write(&mut port_2, DATA2);
    port_2
        .flush()
        .expect(format!("unable to flush serial port {}", port_b).as_str());

    // port 1 should now be readable
    common::expect_events(
        &mut poll,
        &mut events,
        vec![common::ExpectEvent::new(TOKEN1, Interest::READABLE)],
    );
    // and be able to read the full data
    common::checked_read(&mut port_1, &mut buf, DATA2);
    // .. before blocking again.
    common::assert_would_block(port_1.read(&mut buf));
}
<commit_msg>add try_clone test<commit_after>mod common;
use mio::{Interest, Token};
use mio_serial::SerialPortBuilderExt;
use std::io::{Read, Write};

const TOKEN1: Token = Token(0);
const TOKEN2: Token = Token(1);

#[test]
fn test_builder_open_async() {
    let fixture = common::setup_virtual_serial_ports();
    let baud_rate = 9600;
    let builder = mio_serial::new(fixture.port_a, baud_rate);

    let stream = builder
        .open_native_async()
        .expect("unable to open serial port");

    common::assert_baud_rate(&stream, baud_rate)
}

#[test]
fn test_native_from_blocking() {
    use std::convert::TryFrom;
    let baud_rate = 9600;

    let fixture = common::setup_virtual_serial_ports();
    let port = fixture.port_a;
    let native_blocking = mio_serial::new(port, baud_rate)
        .open_native()
        .expect(format!("unable to open serial port {}", port).as_str());

    let stream = mio_serial::SerialStream::try_from(native_blocking)
        .expect("unable to convert from blocking serial port object");

    common::assert_baud_rate(&stream, baud_rate)
}

#[test]
fn test_stream_open() {
    let baud_rate = 9600;
    let fixture = common::setup_virtual_serial_ports();
    let port = fixture.port_a;
    let builder = mio_serial::new(port, baud_rate);
    let stream = mio_serial::SerialStream::open(&builder).expect("unable to open serial port");

    common::assert_baud_rate(&stream, baud_rate)
}

/// Port enumeration doesn't seem to work on virtual serial ports created by com0com during
/// the CI process
#[test]
#[ignore = "Port enumeration test does not seem to work with com0com virtual ports"]
fn test_port_enumeration() {
    let fixture = common::setup_virtual_serial_ports();
    let ports = mio_serial::available_ports().expect("unable to enumerate serial ports");
    for name in [fixture.port_a, fixture.port_b].iter() {
        ports.iter().find(|&info| info.port_name == *name).expect(
            format!(
                "unable to find serial port named {} in enumerated ports",
                name
            )
            .as_str(),
        );
    }
}

#[test]
fn test_read_write_pair() {
    let baud_rate = 38400;

    const DATA1: &[u8] = b"Here is an example string";
    const DATA2: &[u8] = b"And here is a reply to the example string";
    const DEFAULT_BUF_SIZE: usize = 64;

    let fixture = common::setup_virtual_serial_ports();
    let (port_a, port_b) = (fixture.port_a, fixture.port_b);
    let (mut poll, mut events) = common::init_with_poll();

    let mut port_1 = mio_serial::new(port_a, baud_rate)
        .open_native_async()
        .expect(format!("unable to open serial port {}", port_a).as_str());
    let mut port_2 = mio_serial::new(port_b, baud_rate)
        .open_native_async()
        .expect(format!("unable to open serial port {}", port_b).as_str());

    // register both serial ports for read and write events
    poll.registry()
        .register(&mut port_1, TOKEN1, Interest::WRITABLE | Interest::READABLE)
        .expect(
            format!(
                "unable to register port {} as readable and writable",
                port_a
            )
            .as_str(),
        );
    poll.registry()
        .register(&mut port_2, TOKEN2, Interest::READABLE | Interest::WRITABLE)
        .expect(
            format!(
                "unable to register port {} as readable and writable",
                port_b
            )
            .as_str(),
        );

    let mut buf = [0u8; DEFAULT_BUF_SIZE];

    // port1 should immediately be writable
    common::expect_events(
        &mut poll,
        &mut events,
        vec![common::ExpectEvent::new(TOKEN1, Interest::WRITABLE)],
    );

    // port2 should be blocking
    common::assert_would_block(port_2.read(&mut buf).into());

    // write data on port 1
    common::checked_write(&mut port_1, DATA1);
    port_1
        .flush()
        .expect(format!("unable to flush serial port {}", port_a).as_str());

    // port 2 should now be readable
    common::expect_events(
        &mut poll,
        &mut events,
        vec![common::ExpectEvent::new(TOKEN2, Interest::READABLE)],
    );

    // read data on port 2
    common::checked_read(&mut port_2, &mut buf, DATA1);

    // port 2 should then return to blocking
    common::assert_would_block(port_2.read(&mut buf));

    // port 1 should be blocking on read for the reply
    common::assert_would_block(port_1.read(&mut buf));

    // send data back on port 2
    common::checked_write(&mut port_2, DATA2);
    port_2
        .flush()
        .expect(format!("unable to flush serial port {}", port_b).as_str());

    // port 1 should now be readable
    common::expect_events(
        &mut poll,
        &mut events,
        vec![common::ExpectEvent::new(TOKEN1, Interest::READABLE)],
    );
    // and be able to read the full data
    common::checked_read(&mut port_1, &mut buf, DATA2);
    // .. before blocking again.
    common::assert_would_block(port_1.read(&mut buf));
}
#[test]
fn test_try_clone_native() {
    const DATA1: &[u8] = b"Here is an example string";
    //const DATA2: &[u8] = b"And here is a reply to the example string";
    const DEFAULT_BUF_SIZE: usize = 64;
    const TOKEN3: Token = Token(2);

    let baud_rate = 9600;
    let fixture = common::setup_virtual_serial_ports();
    let (mut poll, mut events) = common::init_with_poll();

    let builder_a = mio_serial::new(fixture.port_a, baud_rate);
    let builder_b = mio_serial::new(fixture.port_b, baud_rate);

    let mut sender =
        mio_serial::SerialStream::open(&builder_a).expect("unable to open serial port");
    let mut receiver =
        mio_serial::SerialStream::open(&builder_b).expect("unable to open serial port");
    let mut cloned_receiver = receiver
        .try_clone_native()
        .expect("unable to clone serial port");

    poll.registry()
        .register(&mut sender, TOKEN1, Interest::WRITABLE | Interest::READABLE)
        .expect("unable to register port as readable and writable");
    poll.registry()
        .register(
            &mut receiver,
            TOKEN2,
            Interest::READABLE | Interest::WRITABLE,
        )
        .expect("unable to register port as readable and writable");

    poll.registry()
        .register(
            &mut cloned_receiver,
            TOKEN3,
            Interest::READABLE | Interest::WRITABLE,
        )
        .expect("unable to register port as readable and writable");
    let mut buf = [0u8; DEFAULT_BUF_SIZE];

    common::expect_events(
        &mut poll,
        &mut events,
        vec![common::ExpectEvent::new(TOKEN1, Interest::WRITABLE)],
    );

    common::assert_would_block(receiver.read(&mut buf).into());
    common::assert_would_block(cloned_receiver.read(&mut buf).into());

    // write data on port 1
    common::checked_write(&mut sender, DATA1);
    sender.flush().expect("unable to flush serial port");

    // port 2 should now be readable
    common::expect_events(
        &mut poll,
        &mut events,
        vec![common::ExpectEvent::new(TOKEN2, Interest::READABLE)],
    );

    common::expect_events(
        &mut poll,
        &mut events,
        vec![common::ExpectEvent::new(TOKEN3, Interest::READABLE)],
    );

    // read data on port 2
    common::checked_read(&mut receiver, &mut buf, DATA1);

    // port 2 should then return to blocking
    common::assert_would_block(receiver.read(&mut buf));
    // port 2 should then return to blocking
    common::assert_would_block(cloned_receiver.read(&mut buf));

    // port 1 should be blocking on read for the reply
    common::assert_would_block(sender.read(&mut buf));

    common::expect_events(
        &mut poll,
        &mut events,
        vec![common::ExpectEvent::new(TOKEN1, Interest::WRITABLE)],
    );

    // write data on port 1
    common::checked_write(&mut sender, DATA1);
    sender.flush().expect("unable to flush serial port");

    // port 2 should now be readable
    common::expect_events(
        &mut poll,
        &mut events,
        vec![common::ExpectEvent::new(TOKEN2, Interest::READABLE)],
    );

    common::expect_events(
        &mut poll,
        &mut events,
        vec![common::ExpectEvent::new(TOKEN3, Interest::READABLE)],
    );

    // read data on port 2
    common::checked_read(&mut cloned_receiver, &mut buf, DATA1);

    // port 2 should then return to blocking
    common::assert_would_block(cloned_receiver.read(&mut buf));
    common::assert_would_block(receiver.read(&mut buf));

    // port 1 should be blocking on read for the reply
    common::assert_would_block(sender.read(&mut buf));
}
<|endoftext|>


<commit_before>use std::fmt;

#[derive(Debug, Clone)]
struct Tree {
    enter: Node,
    left: Option<Box<Tree>>,
    right: Option<Box<Tree>>,
}

/*impl fmt::Display for Tree {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "(this: {:#?}, \nleft: {:#?}, \nright: {:#?})",
            self.enter, self.left, self.right
        )
    }
}*/

//for red-black tree
#[derive(Debug, Clone, PartialEq)]
enum Color {
    Black,
    Red,
    White,
}

#[derive(Debug, Clone)]
struct Node {
    val: i32,
    color: Color,
}

impl Node {
    fn new(v: &i32) -> Node {
        Node {
            val: *v,
            color: Color::White,
        }
    }

    fn new_black(v: &i32) -> Node {
        let mut n = Node::new(v);
        n.make_black();
        n
    }
    fn new_red(v: &i32) -> Node {
        let mut n = Node::new(v);
        n.make_red();
        n
    }
    fn make_black(&mut self) {
        self.color = Color::Black;
    }

    fn make_red(&mut self) {
        self.color = Color::Red;
    }

    fn change_color(&mut self) {
        if self.color == Color::Black {
            self.color = Color::Red
        } else {
            self.color = Color::Black
        }
    }
}

type ReTr<'a> = Result<&'a mut Tree, String>;

impl Tree {
    fn new(v: &i32) -> Tree {
        let mut root = Node::new(v);
        root.make_black();
        Tree {
            enter: root,
            left: None,
            right: None,
        }
    }

    //fix color at ending of insert method
    fn insert(&mut self, v: &i32) {
        if *v == self.enter.val {
            println!("{}", "duplicate value");
            return;
        }

        {
            //need drop target which hold self ownship..
            //we need this ownship to fix color at endding of this method.
            let target = if *v > self.enter.val {
                &mut self.right
            } else {
                &mut self.left
            };

            match target {
                Some(next) => next.insert(v),
                None => {
                    let mut new_node = Node::new(v);
                    new_node.make_red();
                    let new_tree = Tree {
                        enter: new_node,
                        left: None,
                        right: None,
                    };
                    *target = Some(Box::new(new_tree));
                }
            }
        }

        //self.fix(v);
    }

    fn look_up_recursive(&mut self, v: &i32) -> ReTr {
        if *v == self.enter.val {
            return Ok(self);
        } else if *v > self.enter.val {
            if let Some(_) = self.right {
                let next = self.right.as_mut().unwrap();
                return next.look_up(v);
            } else {
                Err("not find".to_string())
            }
        } else {
            if let Some(_) = self.left {
                let next = self.left.as_mut().unwrap();
                return next.look_up(v);
            } else {
                Err("not find".to_string())
            }
        }
    }

    fn look_up(&mut self, v: &i32) -> ReTr {
        let mut this: &mut Self = self;
        loop {
            if *v == this.enter.val {
                return Ok(this);
            } else if *v > this.enter.val {
                if let None = this.right {
                    return Err("not find".to_string());
                }
                this = { this }.right.as_mut().unwrap();
            } else {
                if let None = this.left {
                    return Err("not find".to_string());
                }
                this = { this }.left.as_mut().unwrap();
            }
        }
    }

    fn look_up_father(&mut self, v: &i32) -> (ReTr, &'static str) {
        let mut this: &mut Self = self;
        let mut result: &str = "None";
        let mut next: &str = "None";
        loop {
            if *v == this.enter.val {
                return (Err("no father".to_string()), "this");
            }

            match (this.right.as_ref(), this.left.as_ref()) {
                (Some(r), Some(l)) => {
                    if r.enter.val == *v {
                        result = "right";
                    } else if l.enter.val == *v {
                        result = "left"
                    }
                }
                (Some(r), None) => {
                    if r.enter.val == *v {
                        result = "right";
                    }
                }
                (None, Some(l)) => {
                    if l.enter.val == *v {
                        result = "left";
                    }
                }
                _ => (),
            }

            if *v > this.enter.val {
                if let None = this.right {
                    return (Err("not find".to_string()), "Error");
                }
                next = "right";
            } else {
                if let None = this.left {
                    return (Err("not find".to_string()), "Error");
                }
                next = "left";
            }

            if result != "None" {
                return (Ok(this), result);
            } else if next == "right" {
                this = { this }.right.as_mut().unwrap();
            } else if next == "left" {
                this = { this }.left.as_mut().unwrap();
            }
        }
    }

    //find father, grandfather, and uncle
    fn look_up_family(
        &mut self,
        v: &i32,
    ) -> (
        Result<i32, &'static str>,
        Result<i32, &'static str>,
        Result<i32, &'static str>,
    ) {
        let this: &mut Self = self;
        let grandfather: i32;
        let father: i32;

        match this.look_up_father(v).0 {
            Ok(n) => {
                father = n.enter.val;
            }
            Err(_) => {
                return (
                    Err("father not find"),
                    Err("grandfather not find"),
                    Err("uncle not find"),
                )
            }
        }

        let uncle_option: &Option<Box<Tree>>;
        match this.look_up_father(&father) {
            (Ok(n), s) => {
                grandfather = n.enter.val;
                match s {
                    "left" => uncle_option = &n.right,
                    _ => uncle_option = &n.left,
                };
            }
            (Err(_), _) => {
                return (
                    Ok(father),
                    Err("grandfather not find"),
                    Err("uncle not find"),
                )
            }
        }

        match uncle_option {
            Some(un) => return (Ok(father), Ok(grandfather), Ok(un.enter.val)),
            _ => return (Ok(father), Ok(grandfather), Err("uncle not find")),
        }
    }

    fn cut_left_tree(&self) -> Option<Box<Self>> {
        self.left.clone()
    }

    fn cut_right_tree(&self) -> Option<Box<Self>> {
        self.right.clone()
    }

    fn left_shift(&mut self, v: &i32) {
        match self.look_up_father(v).0 {
            Ok(r) => {
                let father = r;
                let mut this = father.cut_left_tree().unwrap();
                let mut son = this.cut_right_tree().unwrap();
                let grand_son = son.cut_left_tree().unwrap();

                this.right = Some(grand_son);
                son.left = Some(this);
                father.left = Some(son);
                return;
            }
            _ => (),
        }

        let left = self.cut_left_tree().unwrap();
        let mut new_left = Tree::new(&self.enter.val);
        new_left.left = Some(left);

        let right = self.cut_right_tree().unwrap();
        let right_left = right.cut_left_tree().unwrap();
        let right_right = right.cut_right_tree().unwrap();
        new_left.right = Some(right_left);

        self.enter = Node::new_black(&right.enter.val);

        self.right = Some(right_right);

        self.left = Some(Box::new(new_left));
    }

    fn right_shift(&mut self, v: &i32) {
        match self.look_up_father(v).0 {
            Ok(r) => {
                let father = r;
                let mut this = father.cut_right_tree().unwrap();
                let mut son = this.cut_left_tree().unwrap();
                let grand_son = son.cut_right_tree();

                this.left = grand_son;
                son.right = Some(this);
                father.right = Some(son);
                return;
            }
            _ => (),
        }

        let right = self.cut_right_tree();
        let left = self.cut_left_tree().unwrap();
        let left_left = left.cut_left_tree().unwrap();
        let left_right = left.cut_right_tree().unwrap();

        let mut new_right = Tree::new(&self.enter.val);
        new_right.left = Some(left_right);
        new_right.right = right;

        self.enter = Node::new_black(&left.enter.val);
        self.left = Some(left_left);
        self.right = Some(Box::new(new_right));
    }

    //this fix method might not very efficiency because look_up_father..
    //always look from top of tree
    fn fix(&mut self, v: &i32) {
        //step 1
        let mut this: i32 = 0;
        match self.look_up_family(v) {
            (Ok(father), Ok(grandfather), Ok(uncle)) => {
                if let Ok(fff) = self.look_up_father(&grandfather).0 {
                    this = fff.enter.val;
                } else {
                    println!("{}", "no great-grandfather");
                    return;
                }

                if let Ok(ff) = self.look_up(&father) {
                    ff.enter.make_black();
                }

                if let Ok(un) = self.look_up(&uncle) {
                    un.enter.make_black();
                }

                if let Ok(ff) = self.look_up(&grandfather) {
                    ff.enter.make_red();
                }
            }
            (a, b, c) => println!("{:#?}, {:#?}, {:#?}", a, b, c),
        }

        //step 2
        self.left_shift(&this);
        this = self
            .look_up(&{ this })
            .unwrap()
            .left
            .as_mut()
            .unwrap()
            .enter
            .val;

        //stap3
        match self.look_up_family(&this) {
            (Ok(father), Ok(grandfather), _) => {
                if let Ok(ff) = self.look_up(&father) {
                    ff.enter.make_black();
                }

                if let Ok(gf) = self.look_up(&grandfather) {
                    gf.enter.make_red();
                    this = gf.enter.val;
                }
            }
            _ => (),
        }

        this = self.look_up_father(&this).0.unwrap().enter.val;
        self.right_shift(&this);
        self.enter.make_black();
    }
}

fn main() {
    //let mut a = Tree::new(&3);
    //a.insert(&2);
    //a.insert(&1);
    //a.insert(&4);
    //a.insert(&5);

    //println!("{:?}", a);
    //println!("{:?}", a.look_up(&1));
    //println!("{:?}", a.look_up_father(&4));
    //println!("{:?}", a);

    let mut b = Tree::new(&10);
    b.insert(&2);
    b.insert(&1);
    b.insert(&5);
    b.insert(&3);
    b.insert(&6);
    b.insert(&11);

    //println!("{:?}", b);
    //println!("{:?}", b.look_up_father(&2));
    let mut c = b.cut_left_tree().unwrap();
    //println!("{:#?}", c);
    c.left_shift(&2);
    println!("{:#?}", c);

    //let mut c = Tree::new(&2);
    //c.insert(&8);
    //c.insert(&1);
    //c.insert(&5);
    //c.insert(&4);
    //c.insert(&7);
    //c.insert(&9);
    //println!("{:?}", c.look_up_father(&8));
    //c.right_shift(&8);
    //println!("{:#?}", c);
}
<commit_msg>change insert method and a bit test cases in main<commit_after>use std::fmt;

#[derive(Debug, Clone)]
struct Tree {
    enter: Node,
    left: Option<Box<Tree>>,
    right: Option<Box<Tree>>,
}

/*impl fmt::Display for Tree {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "(this: {:#?}, \nleft: {:#?}, \nright: {:#?})",
            self.enter, self.left, self.right
        )
    }
}*/

//for red-black tree
#[derive(Debug, Clone, PartialEq)]
enum Color {
    Black,
    Red,
    White,
}

#[derive(Debug, Clone)]
struct Node {
    val: i32,
    color: Color,
}

impl Node {
    fn new(v: &i32) -> Node {
        Node {
            val: *v,
            color: Color::White,
        }
    }

    fn new_black(v: &i32) -> Node {
        let mut n = Node::new(v);
        n.make_black();
        n
    }
    fn new_red(v: &i32) -> Node {
        let mut n = Node::new(v);
        n.make_red();
        n
    }
    fn make_black(&mut self) {
        self.color = Color::Black;
    }

    fn make_red(&mut self) {
        self.color = Color::Red;
    }

    fn change_color(&mut self) {
        if self.color == Color::Black {
            self.color = Color::Red
        } else {
            self.color = Color::Black
        }
    }
}

type ReTr<'a> = Result<&'a mut Tree, String>;

impl Tree {
    fn new(v: &i32) -> Tree {
        let mut root = Node::new(v);
        root.make_black();
        Tree {
            enter: root,
            left: None,
            right: None,
        }
    }

    //fix color at ending of insert method
    fn insert_recursive(&mut self, v: &i32) {
        if *v == self.enter.val {
            println!("{}", "duplicate value");
            return;
        }

        let color_this: Color;
        //need drop target which hold self ownship..
        //we need this ownship to fix color at endding of this method.
        {
            let target = if *v > self.enter.val {
                &mut self.right
            } else {
                &mut self.left
            };

            match target {
                Some(next) => next.insert(v),
                None => {
                    let mut new_node = Node::new(v);
                    new_node.make_red();
                    let new_tree = Tree {
                        enter: new_node,
                        left: None,
                        right: None,
                    };
                    *target = Some(Box::new(new_tree));
                }
            }
        }
    }

    fn insert(&mut self, v: &i32) {
        let mut color: Color;

        {
            let mut this: &mut Self = self;
            loop {
                if *v == this.enter.val {
                    println!("{}", "duplicate value");
                    return;
                }

                if *v > this.enter.val {
                    if let Some(_) = this.right {
                        this = { this }.right.as_mut().unwrap();
                        continue;
                    } else {
                        let mut new_node = Node::new(v);
                        new_node.make_red();
                        let new_tree = Tree {
                            enter: new_node,
                            left: None,
                            right: None,
                        };
                        this.right = Some(Box::new(new_tree));
                        color = this.enter.color.clone();
                        break;
                    }
                }

                if *v < this.enter.val {
                    if let Some(_) = this.left {
                        this = { this }.left.as_mut().unwrap();
                        continue;
                    } else {
                        let mut new_node = Node::new(v);
                        new_node.make_red();
                        let new_tree = Tree {
                            enter: new_node,
                            left: None,
                            right: None,
                        };
                        this.left = Some(Box::new(new_tree));
                        color = this.enter.color.clone();
                        break;
                    }
                }
            }
        }

        if color == Color::Red {
            println!("{}", "fix here");
            //self.fix(v);
        }
    }

    fn look_up_recursive(&mut self, v: &i32) -> ReTr {
        if *v == self.enter.val {
            return Ok(self);
        } else if *v > self.enter.val {
            if let Some(_) = self.right {
                let next = self.right.as_mut().unwrap();
                return next.look_up(v);
            } else {
                Err("not find".to_string())
            }
        } else {
            if let Some(_) = self.left {
                let next = self.left.as_mut().unwrap();
                return next.look_up(v);
            } else {
                Err("not find".to_string())
            }
        }
    }

    fn look_up(&mut self, v: &i32) -> ReTr {
        let mut this: &mut Self = self;
        loop {
            if *v == this.enter.val {
                return Ok(this);
            } else if *v > this.enter.val {
                if let None = this.right {
                    return Err("not find".to_string());
                }
                this = { this }.right.as_mut().unwrap();
            } else {
                if let None = this.left {
                    return Err("not find".to_string());
                }
                this = { this }.left.as_mut().unwrap();
            }
        }
    }

    fn look_up_father(&mut self, v: &i32) -> (ReTr, &'static str) {
        let mut this: &mut Self = self;
        let mut result: &str = "None";
        let mut next: &str = "None";
        loop {
            if *v == this.enter.val {
                return (Err("no father".to_string()), "this");
            }

            match (this.right.as_ref(), this.left.as_ref()) {
                (Some(r), Some(l)) => {
                    if r.enter.val == *v {
                        result = "right";
                    } else if l.enter.val == *v {
                        result = "left"
                    }
                }
                (Some(r), None) => {
                    if r.enter.val == *v {
                        result = "right";
                    }
                }
                (None, Some(l)) => {
                    if l.enter.val == *v {
                        result = "left";
                    }
                }
                _ => (),
            }

            if *v > this.enter.val {
                if let None = this.right {
                    return (Err("not find".to_string()), "Error");
                }
                next = "right";
            } else {
                if let None = this.left {
                    return (Err("not find".to_string()), "Error");
                }
                next = "left";
            }

            if result != "None" {
                return (Ok(this), result);
            } else if next == "right" {
                this = { this }.right.as_mut().unwrap();
            } else if next == "left" {
                this = { this }.left.as_mut().unwrap();
            }
        }
    }

    //find father, grandfather, and uncle
    fn look_up_family(
        &mut self,
        v: &i32,
    ) -> (
        Result<i32, &'static str>,
        Result<i32, &'static str>,
        Result<i32, &'static str>,
    ) {
        let this: &mut Self = self;
        let grandfather: i32;
        let father: i32;

        match this.look_up_father(v).0 {
            Ok(n) => {
                father = n.enter.val;
            }
            Err(_) => {
                return (
                    Err("father not find"),
                    Err("grandfather not find"),
                    Err("uncle not find"),
                )
            }
        }

        let uncle_option: &Option<Box<Tree>>;
        match this.look_up_father(&father) {
            (Ok(n), s) => {
                grandfather = n.enter.val;
                match s {
                    "left" => uncle_option = &n.right,
                    _ => uncle_option = &n.left,
                };
            }
            (Err(_), _) => {
                return (
                    Ok(father),
                    Err("grandfather not find"),
                    Err("uncle not find"),
                )
            }
        }

        match uncle_option {
            Some(un) => return (Ok(father), Ok(grandfather), Ok(un.enter.val)),
            _ => return (Ok(father), Ok(grandfather), Err("uncle not find")),
        }
    }

    fn cut_left_tree(&self) -> Option<Box<Self>> {
        self.left.clone()
    }

    fn cut_right_tree(&self) -> Option<Box<Self>> {
        self.right.clone()
    }

    fn left_shift(&mut self, v: &i32) {
        match self.look_up_father(v).0 {
            Ok(r) => {
                let father = r;
                let mut this = father.cut_left_tree().unwrap();
                let mut son = this.cut_right_tree().unwrap();
                let grand_son = son.cut_left_tree().unwrap();

                this.right = Some(grand_son);
                son.left = Some(this);
                father.left = Some(son);
                return;
            }
            _ => (),
        }

        let left = self.cut_left_tree().unwrap();
        let mut new_left = Tree::new(&self.enter.val);
        new_left.left = Some(left);

        let right = self.cut_right_tree().unwrap();
        let right_left = right.cut_left_tree().unwrap();
        let right_right = right.cut_right_tree().unwrap();
        new_left.right = Some(right_left);

        self.enter = Node::new_black(&right.enter.val);

        self.right = Some(right_right);

        self.left = Some(Box::new(new_left));
    }

    fn right_shift(&mut self, v: &i32) {
        match self.look_up_father(v).0 {
            Ok(r) => {
                let father = r;
                let mut this = father.cut_right_tree().unwrap();
                let mut son = this.cut_left_tree().unwrap();
                let grand_son = son.cut_right_tree();

                this.left = grand_son;
                son.right = Some(this);
                father.right = Some(son);
                return;
            }
            _ => (),
        }

        let right = self.cut_right_tree();
        let left = self.cut_left_tree().unwrap();
        let left_left = left.cut_left_tree().unwrap();
        let left_right = left.cut_right_tree().unwrap();

        let mut new_right = Tree::new(&self.enter.val);
        new_right.left = Some(left_right);
        new_right.right = right;

        self.enter = Node::new_black(&left.enter.val);
        self.left = Some(left_left);
        self.right = Some(Box::new(new_right));
    }

    //this fix method might not very efficiency because look_up_father..
    //always look from top of tree
    fn fix(&mut self, v: &i32) {
        //step 1
        let mut this: i32 = 0;
        match self.look_up_family(v) {
            (Ok(father), Ok(grandfather), Ok(uncle)) => {
                if let Ok(fff) = self.look_up_father(&grandfather).0 {
                    this = fff.enter.val;
                } else {
                    println!("{}", "no great-grandfather");
                    return;
                }

                if let Ok(ff) = self.look_up(&father) {
                    ff.enter.make_black();
                }

                if let Ok(un) = self.look_up(&uncle) {
                    un.enter.make_black();
                }

                if let Ok(ff) = self.look_up(&grandfather) {
                    ff.enter.make_red();
                }
            }
            (a, b, c) => println!("{:#?}, {:#?}, {:#?}", a, b, c),
        }

        //step 2
        self.left_shift(&this);
        this = self
            .look_up(&{ this })
            .unwrap()
            .left
            .as_mut()
            .unwrap()
            .enter
            .val;

        //stap3
        match self.look_up_family(&this) {
            (Ok(father), Ok(grandfather), _) => {
                if let Ok(ff) = self.look_up(&father) {
                    ff.enter.make_black();
                }

                if let Ok(gf) = self.look_up(&grandfather) {
                    gf.enter.make_red();
                    this = gf.enter.val;
                }
            }
            _ => (),
        }

        this = self.look_up_father(&this).0.unwrap().enter.val;
        self.right_shift(&this);
        self.enter.make_black();
    }
}

fn main() {
    //let mut a = Tree::new(&3);
    //a.insert(&2);
    //a.insert(&1);
    //a.insert(&4);
    //a.insert(&5);

    //println!("{:?}", a);
    //println!("{:?}", a.look_up(&1));
    //println!("{:?}", a.look_up_father(&4));
    //println!("{:?}", a);

    //let mut b = Tree::new(&10);
    //b.insert(&2);
    //b.insert(&1);
    //b.insert(&5);
    //b.insert(&3);
    //b.insert(&6);
    //b.insert(&11);

    //println!("{:#?}", b);
    //println!("{:?}", b.look_up_father(&2));
    //let mut c = b.cut_left_tree().unwrap();
    //println!("{:#?}", c);
    //c.left_shift(&2);
    //println!("{:#?}", c);
    //println!("{:#?}", b.look_up_family(&1));
    //println!("{:#?}", b.look_up_family(&2));
    //println!("{:#?}", b.look_up_family(&10));

    let mut c = Tree::new(&11);
    c.insert(&2);
    c.insert(&14);
    c.insert(&1);
    c.insert(&7);
    c.insert(&13);
    c.insert(&8);
    c.insert(&5);
    c.insert(&4);
    //c.fix(&4);
    //println!("{:#?}", c.look_up_father(&4));
    //c.left_shift(&2);
    println!("{:#?}", c);
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::collections::hash_map::Keys;
use std::cell::RefCell;
use std::ops::Index;
use std::path::Path;

use super::{Buffer, BufferId};

/// Creates, manages and deletes all the buffers in Qork, maintaining the various invariants that
/// we expect from the buffers. Firstly, if a buffer is backed by a file, a second buffer on that
/// file cannot be created. Secondly, all buffers have unique identity.
///
/// Note that a Buffer is very different from a BufferView.
pub struct BufferCollection {
    current_buffer: BufferId,
    buffers: HashMap<BufferId, RefCell<Buffer>>
}

impl BufferCollection {
    pub fn new() -> BufferCollection {
        BufferCollection {
            current_buffer: -1,
            buffers: HashMap::with_capacity(20)
        }
    }

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

    pub fn current_buffer(&self) -> BufferId {
        self.current_buffer
    }

    pub fn set_current_buffer(&mut self, buffer_id: BufferId) -> bool {
        if self.buffers.contains_key(&buffer_id) {
            self.current_buffer = buffer_id;
            return true;
        } else {
            return false;
        }
    }

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

    pub fn get(&self, buffer_id: BufferId) -> Option<&RefCell<Buffer>> {
         self.buffers.get(&buffer_id)
    }

    pub fn keys(&self) -> Keys<BufferId, RefCell<Buffer>> {
         self.buffers.keys()
    }

    pub fn insert(&mut self, buffer: Buffer) {
        self.buffers.insert(buffer.id(), RefCell::new(buffer));
    }

    pub fn remove(&mut self, buffer_id: BufferId) -> Option<RefCell<Buffer>> {
        self.buffers.remove(&buffer_id)
    }

    pub fn find_by_filename<P : AsRef<Path>>(&mut self, filename: P) -> Option<&RefCell<Buffer>> {
        self.buffers.values().find(|refcell| refcell.borrow().filename.as_ref().map_or(false, |f| f == filename.as_ref()))
    }

    // Needs a buffer factory passed in. Check to see if the file is already open. If it is, return
    // the id of the first buffer rather than creating a new one.
    pub fn open_file() {}
    // Saves a buffer, but only if it already has a filename. Set changed to false.
    pub fn save_buffer() {}
    // Saves a buffer to a specific filename. Might need to allocate a new title. Can change
    // the filename that a buffer is saved to. Set changed to false.
    pub fn save_buffer_as() {}
    // Not sure we need this, it is really just remove disguised.
    pub fn close_buffer() {}

    // We also need a filename pre-processor better than just expand_variables.
    // It should be able to deal with relative names, trying to find a file relative to the
    // current buffer's directory (for working in projects), or failing that, to the cwd.

    /// Title algorithm. We need the ability to uniqueify buffer names. Once a suffix number is
    /// assigned it is never changed. They can be reused, or even not used (we only allocate them
    /// for our convenience, and they do not need to go up monotonically like buffer ids do).
    /// For new buffers not backed by a file "new", then "new 1 " etc.
    /// For buffers backed by a file, the leaf filename, then '1' etc.
    fn get_unique_title(&self, proposed: &str) -> String {
        //let matching_buffers : Vec<_> = self.buffers.values().filter(
        //    |refcell| refcell.borrow().title == proposed).collect();

        let prefix = String::from(proposed) + " ";
        let matching_buffers = self.buffers.values()
            .filter(|refcell| refcell.borrow().title == proposed || refcell.borrow().title.starts_with(&prefix));

        let cnt = matching_buffers.count();
        if cnt == 0 {
            return String::from(proposed);
        } else if cnt == 1 {
            return String::from(proposed) + " 1";
        }

        String::default()
    }
}

impl Index<BufferId> for BufferCollection {
    type Output = RefCell<Buffer>;

    fn index(&self, buffer_id: BufferId) -> &RefCell<Buffer> {
        &self.buffers[&buffer_id]
    }
}

#[cfg(test)]
mod buffer_collection_tests {
    use super::*;
    use super::super::BufferFactory;

    #[test]
    fn get_unique_title_for_empty_collection_returns_proposed() {
        let bc = BufferCollection::new();
        let proposed = "new";
        let title = bc.get_unique_title(proposed);
        assert_eq!(title, proposed);
    }

    #[test]
    fn get_unique_title_for_collection_with_no_matching_buffer_title_returns_proposed() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();

        let mut b = fac.new_empty_buffer();
        b.title = String::from("t1");
        bc.insert(b);

        let mut b = fac.new_empty_buffer();
        b.title = String::from("t2");
        bc.insert(b);

        let proposed = "new";
        let title = bc.get_unique_title(proposed);
        assert_eq!(title, proposed);
    }

    #[test]
    fn get_unique_title_for_collection_with_matching_buffer_title_returns_proposed_with_numeral_of_one() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();

        let mut b = fac.new_empty_buffer();
        b.title = String::from("new");
        bc.insert(b);

        let proposed = "new";
        let title = bc.get_unique_title(proposed);
        assert_eq!(title, "new 1");
    }

    #[test]
    fn get_unique_title_for_collection_with_matching_buffer_titles_in_ascending_order_returns_proposed_with_next_free_numeral() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();

        let mut b = fac.new_empty_buffer();
        b.title = String::from("new");
        bc.insert(b);

        let mut b = fac.new_empty_buffer();
        b.title = String::from("new 1");
        bc.insert(b);

        let mut b = fac.new_empty_buffer();
        b.title = String::from("new 2");
        bc.insert(b);

        let proposed = "new";
        let title = bc.get_unique_title(proposed);
        assert_eq!(title, "new 3");
    }

    #[test]
    fn get_unique_title_for_collection_with_matching_buffer_titles_with_gap_returns_proposed_with_lowest_free_numeral() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();

        let mut b = fac.new_empty_buffer();
        b.title = String::from("new");
        bc.insert(b);

        let mut b = fac.new_empty_buffer();
        b.title = String::from("new 1");
        bc.insert(b);

        let mut b = fac.new_empty_buffer();
        b.title = String::from("new 3");
        bc.insert(b);

        let proposed = "new";
        let title = bc.get_unique_title(proposed);
        assert_eq!(title, "new 2");
    }

    #[test]
    fn is_empty_for_empty_collection_returns_true() {
        let bc = BufferCollection::new();
        assert!(bc.is_empty());
    }

    #[test]
    fn len_for_empty_collection_returns_zero() {
        let bc = BufferCollection::new();
        assert_eq!(0, bc.len());
    }

    #[test]
    fn len_for_non_empty_collection_returns_length() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();
        let b = fac.new_empty_buffer();
        bc.insert(b);

        assert_eq!(1, bc.len());
    }

    #[test]
    fn get_for_empty_collection_returns_false() {
        let bc = BufferCollection::new();
        assert!(bc.get(0).is_none());
    }

    #[test]
    fn get_for_id_not_in_collection_returns_none() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();
        let b = fac.new_empty_buffer();
        let id = b.id;
        bc.insert(b);
        assert!(bc.get(id + 1).is_none());
    }

    #[test]
    fn get_for_id_in_collection_returns_buffer() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();
        let b = fac.new_empty_buffer();
        let id = b.id;
        bc.insert(b);

        let result = bc.get(id).unwrap().borrow();
        assert_eq!(id, result.id());

    }

    #[test]
    fn remove_for_non_existent_buffer_returns_none() {
        let mut bc = BufferCollection::new();
        assert_eq!(bc.remove(1), None);
    }

    #[test]
    fn remove_for_buffer_in_collection_returns_buffer() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();
        let b = fac.new_empty_buffer();
        let id = b.id;
        bc.insert(b);

        let b2 = bc.remove(id).unwrap().into_inner();
        assert_eq!(id, b2.id());
        assert_eq!(0, bc.len());
    }

    #[test]
    fn find_by_filename_for_filename_not_in_collection_returns_none() {
        let mut bc = BufferCollection::new();
        let result = bc.find_by_filename("/c/temp/feeeegfxgdg");
        assert_eq!(result, None);
    }

    #[test]
    fn find_by_filename_for_filename_in_collection_returns_buffer() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();
        let b = fac.open_file("/c/foo.txt");
        let id = b.id;
        bc.insert(b);

        let result = bc.find_by_filename("/c/foo.txt").unwrap();
        assert_eq!(result.borrow().id(), id);
    }
}
<commit_msg>Buffers: we have a working get_unique_title.<commit_after>use std::collections::HashMap;
use std::collections::hash_map::Keys;
use std::cell::RefCell;
use std::ops::Index;
use std::path::Path;

use super::{Buffer, BufferId};

/// Creates, manages and deletes all the buffers in Qork, maintaining the various invariants that
/// we expect from the buffers. Firstly, if a buffer is backed by a file, a second buffer on that
/// file cannot be created. Secondly, all buffers have unique identity.
///
/// Note that a Buffer is very different from a BufferView.
pub struct BufferCollection {
    current_buffer: BufferId,
    buffers: HashMap<BufferId, RefCell<Buffer>>
}

impl BufferCollection {
    pub fn new() -> BufferCollection {
        BufferCollection {
            current_buffer: -1,
            buffers: HashMap::with_capacity(20)
        }
    }

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

    pub fn current_buffer(&self) -> BufferId {
        self.current_buffer
    }

    pub fn set_current_buffer(&mut self, buffer_id: BufferId) -> bool {
        if self.buffers.contains_key(&buffer_id) {
            self.current_buffer = buffer_id;
            return true;
        } else {
            return false;
        }
    }

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

    pub fn get(&self, buffer_id: BufferId) -> Option<&RefCell<Buffer>> {
         self.buffers.get(&buffer_id)
    }

    pub fn keys(&self) -> Keys<BufferId, RefCell<Buffer>> {
         self.buffers.keys()
    }

    pub fn insert(&mut self, buffer: Buffer) {
        self.buffers.insert(buffer.id(), RefCell::new(buffer));
    }

    pub fn remove(&mut self, buffer_id: BufferId) -> Option<RefCell<Buffer>> {
        self.buffers.remove(&buffer_id)
    }

    pub fn find_by_filename<P : AsRef<Path>>(&mut self, filename: P) -> Option<&RefCell<Buffer>> {
        self.buffers.values().find(|refcell| refcell.borrow().filename.as_ref().map_or(false, |f| f == filename.as_ref()))
    }

    // Needs a buffer factory passed in. Check to see if the file is already open. If it is, return
    // the id of the first buffer rather than creating a new one.
    pub fn open_file() {}
    // Saves a buffer, but only if it already has a filename. Set changed to false.
    pub fn save_buffer() {}
    // Saves a buffer to a specific filename. Might need to allocate a new title. Can change
    // the filename that a buffer is saved to. Set changed to false.
    pub fn save_buffer_as() {}
    // Not sure we need this, it is really just remove disguised.
    pub fn close_buffer() {}

    // We also need a filename pre-processor better than just expand_variables.
    // It should be able to deal with relative names, trying to find a file relative to the
    // current buffer's directory (for working in projects), or failing that, to the cwd.

    /// Title algorithm. We need the ability to uniqueify buffer names. Once a suffix number is
    /// assigned it is never changed. They can be reused, or even not used (we only allocate them
    /// for our convenience, and they do not need to go up monotonically like buffer ids do).
    /// For new buffers not backed by a file "new", then "new 1 " etc.
    /// For buffers backed by a file, the leaf filename, then '1' etc.
    fn get_unique_title(&self, proposed: &str) -> String {
        let prefix = String::from(proposed) + " ";
        let matching_buffers : Vec<String> = self.buffers.values()
            .map(|refcell| refcell.borrow())
            .map(|x| x.title.clone())
            .filter(|title| *title == String::from(proposed) || title.starts_with(&prefix))
            .collect();

        let namer = |n: i32| -> String {
            if n == 0 {
                return String::from(proposed)
            } else {
                return String::from(proposed) + " " + &n.to_string()
            }
        };

        let mut i = 0;
        loop {
            let p = namer(i);
            if !matching_buffers.contains(&p) {
                return p
            } else {
                i += 1
            }
        }
    }
}

impl Index<BufferId> for BufferCollection {
    type Output = RefCell<Buffer>;

    fn index(&self, buffer_id: BufferId) -> &RefCell<Buffer> {
        &self.buffers[&buffer_id]
    }
}

#[cfg(test)]
mod buffer_collection_tests {
    use super::*;
    use super::super::BufferFactory;

    #[test]
    fn get_unique_title_for_empty_collection_returns_proposed() {
        let bc = BufferCollection::new();
        let proposed = "new";
        let title = bc.get_unique_title(proposed);
        assert_eq!(title, proposed);
    }

    #[test]
    fn get_unique_title_for_collection_with_no_matching_buffer_title_returns_proposed() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();

        let mut b = fac.new_empty_buffer();
        b.title = String::from("t1");
        bc.insert(b);

        let mut b = fac.new_empty_buffer();
        b.title = String::from("t2");
        bc.insert(b);

        let proposed = "new";
        let title = bc.get_unique_title(proposed);
        assert_eq!(title, proposed);
    }

    #[test]
    fn get_unique_title_for_collection_with_matching_buffer_title_returns_proposed_with_numeral_of_one() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();

        let mut b = fac.new_empty_buffer();
        b.title = String::from("new");
        bc.insert(b);

        let proposed = "new";
        let title = bc.get_unique_title(proposed);
        assert_eq!(title, "new 1");
    }

    #[test]
    fn get_unique_title_for_collection_with_matching_buffer_titles_in_ascending_order_returns_proposed_with_next_free_numeral() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();

        let mut b = fac.new_empty_buffer();
        b.title = String::from("new");
        bc.insert(b);

        let mut b = fac.new_empty_buffer();
        b.title = String::from("new 1");
        bc.insert(b);

        let mut b = fac.new_empty_buffer();
        b.title = String::from("new 2");
        bc.insert(b);

        let proposed = "new";
        let title = bc.get_unique_title(proposed);
        assert_eq!(title, "new 3");
    }

    #[test]
    fn get_unique_title_for_collection_with_matching_buffer_titles_with_gap_returns_proposed_with_lowest_free_numeral() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();

        let mut b = fac.new_empty_buffer();
        b.title = String::from("new");
        bc.insert(b);

        let mut b = fac.new_empty_buffer();
        b.title = String::from("new 1");
        bc.insert(b);

        let mut b = fac.new_empty_buffer();
        b.title = String::from("new 3");
        bc.insert(b);

        let proposed = "new";
        let title = bc.get_unique_title(proposed);
        assert_eq!(title, "new 2");
    }

    #[test]
    fn is_empty_for_empty_collection_returns_true() {
        let bc = BufferCollection::new();
        assert!(bc.is_empty());
    }

    #[test]
    fn len_for_empty_collection_returns_zero() {
        let bc = BufferCollection::new();
        assert_eq!(0, bc.len());
    }

    #[test]
    fn len_for_non_empty_collection_returns_length() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();
        let b = fac.new_empty_buffer();
        bc.insert(b);

        assert_eq!(1, bc.len());
    }

    #[test]
    fn get_for_empty_collection_returns_false() {
        let bc = BufferCollection::new();
        assert!(bc.get(0).is_none());
    }

    #[test]
    fn get_for_id_not_in_collection_returns_none() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();
        let b = fac.new_empty_buffer();
        let id = b.id;
        bc.insert(b);
        assert!(bc.get(id + 1).is_none());
    }

    #[test]
    fn get_for_id_in_collection_returns_buffer() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();
        let b = fac.new_empty_buffer();
        let id = b.id;
        bc.insert(b);

        let result = bc.get(id).unwrap().borrow();
        assert_eq!(id, result.id());

    }

    #[test]
    fn remove_for_non_existent_buffer_returns_none() {
        let mut bc = BufferCollection::new();
        assert_eq!(bc.remove(1), None);
    }

    #[test]
    fn remove_for_buffer_in_collection_returns_buffer() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();
        let b = fac.new_empty_buffer();
        let id = b.id;
        bc.insert(b);

        let b2 = bc.remove(id).unwrap().into_inner();
        assert_eq!(id, b2.id());
        assert_eq!(0, bc.len());
    }

    #[test]
    fn find_by_filename_for_filename_not_in_collection_returns_none() {
        let mut bc = BufferCollection::new();
        let result = bc.find_by_filename("/c/temp/feeeegfxgdg");
        assert_eq!(result, None);
    }

    #[test]
    fn find_by_filename_for_filename_in_collection_returns_buffer() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();
        let b = fac.open_file("/c/foo.txt");
        let id = b.id;
        bc.insert(b);

        let result = bc.find_by_filename("/c/foo.txt").unwrap();
        assert_eq!(result.borrow().id(), id);
    }
}
<|endoftext|>