<commit_before>//! FIXME: write short doc here

use rustc_hash::FxHashSet;

use syntax::{
    ast::{self, AstNode, AstToken, VisibilityOwner},
    Direction, NodeOrToken, SourceFile,
    SyntaxKind::{self, *},
    SyntaxNode, TextRange, TextSize,
};

#[derive(Debug, PartialEq, Eq)]
pub enum FoldKind {
    Comment,
    Imports,
    Mods,
    Block,
    ArgList,
    Region,
    Consts,
    Statics,
}

#[derive(Debug)]
pub struct Fold {
    pub range: TextRange,
    pub kind: FoldKind,
}

pub(crate) fn folding_ranges(file: &SourceFile) -> Vec<Fold> {
    let mut res = vec![];
    let mut visited_comments = FxHashSet::default();
    let mut visited_imports = FxHashSet::default();
    let mut visited_mods = FxHashSet::default();
    let mut visited_consts = FxHashSet::default();
    // regions can be nested, here is a LIFO buffer
    let mut regions_starts: Vec<TextSize> = vec![];

    for element in file.syntax().descendants_with_tokens() {
        // Fold items that span multiple lines
        if let Some(kind) = fold_kind(element.kind()) {
            let is_multiline = match &element {
                NodeOrToken::Node(node) => node.text().contains_char('\n'),
                NodeOrToken::Token(token) => token.text().contains('\n'),
            };
            if is_multiline {
                res.push(Fold { range: element.text_range(), kind });
                continue;
            }
        }

        match element {
            NodeOrToken::Token(token) => {
                // Fold groups of comments
                if let Some(comment) = ast::Comment::cast(token) {
                    if !visited_comments.contains(&comment) {
                        // regions are not real comments
                        if comment.text().trim().starts_with("// region:") {
                            regions_starts.push(comment.syntax().text_range().start());
                        } else if comment.text().trim().starts_with("// endregion") {
                            if let Some(region) = regions_starts.pop() {
                                res.push(Fold {
                                    range: TextRange::new(
                                        region,
                                        comment.syntax().text_range().end(),
                                    ),
                                    kind: FoldKind::Region,
                                })
                            }
                        } else {
                            if let Some(range) =
                                contiguous_range_for_comment(comment, &mut visited_comments)
                            {
                                res.push(Fold { range, kind: FoldKind::Comment })
                            }
                        }
                    }
                }
            }
            NodeOrToken::Node(node) => {
                // Fold groups of imports
                if node.kind() == USE && !visited_imports.contains(&node) {
                    if let Some(range) = contiguous_range_for_group(&node, &mut visited_imports) {
                        res.push(Fold { range, kind: FoldKind::Imports })
                    }
                }

                // Fold groups of mods
                if node.kind() == MODULE && !has_visibility(&node) && !visited_mods.contains(&node)
                {
                    if let Some(range) =
                        contiguous_range_for_group_unless(&node, has_visibility, &mut visited_mods)
                    {
                        res.push(Fold { range, kind: FoldKind::Mods })
                    }
                }

                // Fold groups of consts
                if node.kind() == CONST && !visited_consts.contains(&node) {
                    if let Some(range) = contiguous_range_for_group(&node, &mut visited_consts) {
                        res.push(Fold { range, kind: FoldKind::Consts })
                    }
                }
            }
        }
    }

    res
}

fn fold_kind(kind: SyntaxKind) -> Option<FoldKind> {
    match kind {
        COMMENT => Some(FoldKind::Comment),
        ARG_LIST | PARAM_LIST => Some(FoldKind::ArgList),
        ASSOC_ITEM_LIST
        | RECORD_FIELD_LIST
        | RECORD_PAT_FIELD_LIST
        | RECORD_EXPR_FIELD_LIST
        | ITEM_LIST
        | EXTERN_ITEM_LIST
        | USE_TREE_LIST
        | BLOCK_EXPR
        | MATCH_ARM_LIST
        | VARIANT_LIST
        | TOKEN_TREE => Some(FoldKind::Block),
        _ => None,
    }
}

fn has_visibility(node: &SyntaxNode) -> bool {
    ast::Module::cast(node.clone()).and_then(|m| m.visibility()).is_some()
}

fn contiguous_range_for_group(
    first: &SyntaxNode,
    visited: &mut FxHashSet<SyntaxNode>,
) -> Option<TextRange> {
    contiguous_range_for_group_unless(first, |_| false, visited)
}

fn contiguous_range_for_group_unless(
    first: &SyntaxNode,
    unless: impl Fn(&SyntaxNode) -> bool,
    visited: &mut FxHashSet<SyntaxNode>,
) -> Option<TextRange> {
    visited.insert(first.clone());

    let mut last = first.clone();
    for element in first.siblings_with_tokens(Direction::Next) {
        let node = match element {
            NodeOrToken::Token(token) => {
                if let Some(ws) = ast::Whitespace::cast(token) {
                    if !ws.spans_multiple_lines() {
                        // Ignore whitespace without blank lines
                        continue;
                    }
                }
                // There is a blank line or another token, which means that the
                // group ends here
                break;
            }
            NodeOrToken::Node(node) => node,
        };

        // Stop if we find a node that doesn't belong to the group
        if node.kind() != first.kind() || unless(&node) {
            break;
        }

        visited.insert(node.clone());
        last = node;
    }

    if first != &last {
        Some(TextRange::new(first.text_range().start(), last.text_range().end()))
    } else {
        // The group consists of only one element, therefore it cannot be folded
        None
    }
}

fn contiguous_range_for_comment(
    first: ast::Comment,
    visited: &mut FxHashSet<ast::Comment>,
) -> Option<TextRange> {
    visited.insert(first.clone());

    // Only fold comments of the same flavor
    let group_kind = first.kind();
    if !group_kind.shape.is_line() {
        return None;
    }

    let mut last = first.clone();
    for element in first.syntax().siblings_with_tokens(Direction::Next) {
        match element {
            NodeOrToken::Token(token) => {
                if let Some(ws) = ast::Whitespace::cast(token.clone()) {
                    if !ws.spans_multiple_lines() {
                        // Ignore whitespace without blank lines
                        continue;
                    }
                }
                if let Some(c) = ast::Comment::cast(token) {
                    if c.kind() == group_kind {
                        // regions are not real comments
                        if c.text().trim().starts_with("// region:")
                            || c.text().trim().starts_with("// endregion")
                        {
                            break;
                        } else {
                            visited.insert(c.clone());
                            last = c;
                            continue;
                        }
                    }
                }
                // The comment group ends because either:
                // * An element of a different kind was reached
                // * A comment of a different flavor was reached
                break;
            }
            NodeOrToken::Node(_) => break,
        };
    }

    if first != last {
        Some(TextRange::new(first.syntax().text_range().start(), last.syntax().text_range().end()))
    } else {
        // The group consists of only one element, therefore it cannot be folded
        None
    }
}

#[cfg(test)]
mod tests {
    use test_utils::extract_tags;

    use super::*;

    fn check(ra_fixture: &str) {
        let (ranges, text) = extract_tags(ra_fixture, "fold");

        let parse = SourceFile::parse(&text);
        let folds = folding_ranges(&parse.tree());
        assert_eq!(
            folds.len(),
            ranges.len(),
            "The amount of folds is different than the expected amount"
        );

        for (fold, (range, attr)) in folds.iter().zip(ranges.into_iter()) {
            assert_eq!(fold.range.start(), range.start());
            assert_eq!(fold.range.end(), range.end());

            let kind = match fold.kind {
                FoldKind::Comment => "comment",
                FoldKind::Imports => "imports",
                FoldKind::Mods => "mods",
                FoldKind::Block => "block",
                FoldKind::ArgList => "arglist",
                FoldKind::Region => "region",
                FoldKind::Consts => "consts",
                FoldKind::Statics => "statics"
            };
            assert_eq!(kind, &attr.unwrap());
        }
    }

    #[test]
    fn test_fold_comments() {
        check(
            r#"
<fold comment>// Hello
// this is a multiline
// comment
//</fold>

// But this is not

fn main() <fold block>{
    <fold comment>// We should
    // also
    // fold
    // this one.</fold>
    <fold comment>//! But this one is different
    //! because it has another flavor</fold>
    <fold comment>/* As does this
    multiline comment */</fold>
}</fold>"#,
        );
    }

    #[test]
    fn test_fold_imports() {
        check(
            r#"
use std::<fold block>{
    str,
    vec,
    io as iop
}</fold>;

fn main() <fold block>{
}</fold>"#,
        );
    }

    #[test]
    fn test_fold_mods() {
        check(
            r#"

pub mod foo;
<fold mods>mod after_pub;
mod after_pub_next;</fold>

<fold mods>mod before_pub;
mod before_pub_next;</fold>
pub mod bar;

mod not_folding_single;
pub mod foobar;
pub not_folding_single_next;

<fold mods>#[cfg(test)]
mod with_attribute;
mod with_attribute_next;</fold>

fn main() <fold block>{
}</fold>"#,
        );
    }

    #[test]
    fn test_fold_import_groups() {
        check(
            r#"
<fold imports>use std::str;
use std::vec;
use std::io as iop;</fold>

<fold imports>use std::mem;
use std::f64;</fold>

<fold imports>use std::collections::HashMap;
// Some random comment
use std::collections::VecDeque;</fold>

fn main() <fold block>{
}</fold>"#,
        );
    }

    #[test]
    fn test_fold_import_and_groups() {
        check(
            r#"
<fold imports>use std::str;
use std::vec;
use std::io as iop;</fold>

<fold imports>use std::mem;
use std::f64;</fold>

use std::collections::<fold block>{
    HashMap,
    VecDeque,
}</fold>;
// Some random comment

fn main() <fold block>{
}</fold>"#,
        );
    }

    #[test]
    fn test_folds_structs() {
        check(
            r#"
struct Foo <fold block>{
}</fold>
"#,
        );
    }

    #[test]
    fn test_folds_traits() {
        check(
            r#"
trait Foo <fold block>{
}</fold>
"#,
        );
    }

    #[test]
    fn test_folds_macros() {
        check(
            r#"
macro_rules! foo <fold block>{
    ($($tt:tt)*) => { $($tt)* }
}</fold>
"#,
        );
    }

    #[test]
    fn test_fold_match_arms() {
        check(
            r#"
fn main() <fold block>{
    match 0 <fold block>{
        0 => 0,
        _ => 1,
    }</fold>
}</fold>
"#,
        );
    }

    #[test]
    fn fold_big_calls() {
        check(
            r#"
fn main() <fold block>{
    frobnicate<fold arglist>(
        1,
        2,
        3,
    )</fold>
}</fold>
"#,
        )
    }

    #[test]
    fn fold_record_literals() {
        check(
            r#"
const _: S = S <fold block>{

}</fold>;
"#,
        )
    }

    #[test]
    fn fold_multiline_params() {
        check(
            r#"
fn foo<fold arglist>(
    x: i32,
    y: String,
)</fold> {}
"#,
        )
    }

    #[test]
    fn fold_region() {
        check(
            r#"
// 1. some normal comment
<fold region>// region: test
// 2. some normal comment
calling_function(x,y);
// endregion: test</fold>
"#,
        )
    }

    #[test]
    fn fold_consecutive_const() {
        check(
            r#"
<fold consts>const FIRST_CONST: &str = "first";
const SECOND_CONST: &str = "second";</fold>
            "#,
        )
    }

    #[test]
    fn fold_consecutive_static() {
        check(
            r#"
<fold statics>static FIRST_STATIC: &str = "first";
static SECOND_STATIC: &str = "second";</fold>
            "#,
        )
    }
}
<commit_msg>Folding range for statics<commit_after>//! FIXME: write short doc here

use rustc_hash::FxHashSet;

use syntax::{
    ast::{self, AstNode, AstToken, VisibilityOwner},
    Direction, NodeOrToken, SourceFile,
    SyntaxKind::{self, *},
    SyntaxNode, TextRange, TextSize,
};

#[derive(Debug, PartialEq, Eq)]
pub enum FoldKind {
    Comment,
    Imports,
    Mods,
    Block,
    ArgList,
    Region,
    Consts,
    Statics,
}

#[derive(Debug)]
pub struct Fold {
    pub range: TextRange,
    pub kind: FoldKind,
}

pub(crate) fn folding_ranges(file: &SourceFile) -> Vec<Fold> {
    let mut res = vec![];
    let mut visited_comments = FxHashSet::default();
    let mut visited_imports = FxHashSet::default();
    let mut visited_mods = FxHashSet::default();
    let mut visited_consts = FxHashSet::default();
    let mut visited_statics = FxHashSet::default();
    // regions can be nested, here is a LIFO buffer
    let mut regions_starts: Vec<TextSize> = vec![];

    for element in file.syntax().descendants_with_tokens() {
        // Fold items that span multiple lines
        if let Some(kind) = fold_kind(element.kind()) {
            let is_multiline = match &element {
                NodeOrToken::Node(node) => node.text().contains_char('\n'),
                NodeOrToken::Token(token) => token.text().contains('\n'),
            };
            if is_multiline {
                res.push(Fold { range: element.text_range(), kind });
                continue;
            }
        }

        match element {
            NodeOrToken::Token(token) => {
                // Fold groups of comments
                if let Some(comment) = ast::Comment::cast(token) {
                    if !visited_comments.contains(&comment) {
                        // regions are not real comments
                        if comment.text().trim().starts_with("// region:") {
                            regions_starts.push(comment.syntax().text_range().start());
                        } else if comment.text().trim().starts_with("// endregion") {
                            if let Some(region) = regions_starts.pop() {
                                res.push(Fold {
                                    range: TextRange::new(
                                        region,
                                        comment.syntax().text_range().end(),
                                    ),
                                    kind: FoldKind::Region,
                                })
                            }
                        } else {
                            if let Some(range) =
                                contiguous_range_for_comment(comment, &mut visited_comments)
                            {
                                res.push(Fold { range, kind: FoldKind::Comment })
                            }
                        }
                    }
                }
            }
            NodeOrToken::Node(node) => {
                // Fold groups of imports
                if node.kind() == USE && !visited_imports.contains(&node) {
                    if let Some(range) = contiguous_range_for_group(&node, &mut visited_imports) {
                        res.push(Fold { range, kind: FoldKind::Imports })
                    }
                }

                // Fold groups of mods
                if node.kind() == MODULE && !has_visibility(&node) && !visited_mods.contains(&node)
                {
                    if let Some(range) =
                        contiguous_range_for_group_unless(&node, has_visibility, &mut visited_mods)
                    {
                        res.push(Fold { range, kind: FoldKind::Mods })
                    }
                }

                // Fold groups of consts
                if node.kind() == CONST && !visited_consts.contains(&node) {
                    if let Some(range) = contiguous_range_for_group(&node, &mut visited_consts) {
                        res.push(Fold { range, kind: FoldKind::Consts })
                    }
                }
                // Fold groups of consts
                if node.kind() == STATIC && !visited_statics.contains(&node) {
                    if let Some(range) = contiguous_range_for_group(&node, &mut visited_statics) {
                        res.push(Fold { range, kind: FoldKind::Statics })
                    }
                }
            }
        }
    }

    res
}

fn fold_kind(kind: SyntaxKind) -> Option<FoldKind> {
    match kind {
        COMMENT => Some(FoldKind::Comment),
        ARG_LIST | PARAM_LIST => Some(FoldKind::ArgList),
        ASSOC_ITEM_LIST
        | RECORD_FIELD_LIST
        | RECORD_PAT_FIELD_LIST
        | RECORD_EXPR_FIELD_LIST
        | ITEM_LIST
        | EXTERN_ITEM_LIST
        | USE_TREE_LIST
        | BLOCK_EXPR
        | MATCH_ARM_LIST
        | VARIANT_LIST
        | TOKEN_TREE => Some(FoldKind::Block),
        _ => None,
    }
}

fn has_visibility(node: &SyntaxNode) -> bool {
    ast::Module::cast(node.clone()).and_then(|m| m.visibility()).is_some()
}

fn contiguous_range_for_group(
    first: &SyntaxNode,
    visited: &mut FxHashSet<SyntaxNode>,
) -> Option<TextRange> {
    contiguous_range_for_group_unless(first, |_| false, visited)
}

fn contiguous_range_for_group_unless(
    first: &SyntaxNode,
    unless: impl Fn(&SyntaxNode) -> bool,
    visited: &mut FxHashSet<SyntaxNode>,
) -> Option<TextRange> {
    visited.insert(first.clone());

    let mut last = first.clone();
    for element in first.siblings_with_tokens(Direction::Next) {
        let node = match element {
            NodeOrToken::Token(token) => {
                if let Some(ws) = ast::Whitespace::cast(token) {
                    if !ws.spans_multiple_lines() {
                        // Ignore whitespace without blank lines
                        continue;
                    }
                }
                // There is a blank line or another token, which means that the
                // group ends here
                break;
            }
            NodeOrToken::Node(node) => node,
        };

        // Stop if we find a node that doesn't belong to the group
        if node.kind() != first.kind() || unless(&node) {
            break;
        }

        visited.insert(node.clone());
        last = node;
    }

    if first != &last {
        Some(TextRange::new(first.text_range().start(), last.text_range().end()))
    } else {
        // The group consists of only one element, therefore it cannot be folded
        None
    }
}

fn contiguous_range_for_comment(
    first: ast::Comment,
    visited: &mut FxHashSet<ast::Comment>,
) -> Option<TextRange> {
    visited.insert(first.clone());

    // Only fold comments of the same flavor
    let group_kind = first.kind();
    if !group_kind.shape.is_line() {
        return None;
    }

    let mut last = first.clone();
    for element in first.syntax().siblings_with_tokens(Direction::Next) {
        match element {
            NodeOrToken::Token(token) => {
                if let Some(ws) = ast::Whitespace::cast(token.clone()) {
                    if !ws.spans_multiple_lines() {
                        // Ignore whitespace without blank lines
                        continue;
                    }
                }
                if let Some(c) = ast::Comment::cast(token) {
                    if c.kind() == group_kind {
                        // regions are not real comments
                        if c.text().trim().starts_with("// region:")
                            || c.text().trim().starts_with("// endregion")
                        {
                            break;
                        } else {
                            visited.insert(c.clone());
                            last = c;
                            continue;
                        }
                    }
                }
                // The comment group ends because either:
                // * An element of a different kind was reached
                // * A comment of a different flavor was reached
                break;
            }
            NodeOrToken::Node(_) => break,
        };
    }

    if first != last {
        Some(TextRange::new(first.syntax().text_range().start(), last.syntax().text_range().end()))
    } else {
        // The group consists of only one element, therefore it cannot be folded
        None
    }
}

#[cfg(test)]
mod tests {
    use test_utils::extract_tags;

    use super::*;

    fn check(ra_fixture: &str) {
        let (ranges, text) = extract_tags(ra_fixture, "fold");

        let parse = SourceFile::parse(&text);
        let folds = folding_ranges(&parse.tree());
        assert_eq!(
            folds.len(),
            ranges.len(),
            "The amount of folds is different than the expected amount"
        );

        for (fold, (range, attr)) in folds.iter().zip(ranges.into_iter()) {
            assert_eq!(fold.range.start(), range.start());
            assert_eq!(fold.range.end(), range.end());

            let kind = match fold.kind {
                FoldKind::Comment => "comment",
                FoldKind::Imports => "imports",
                FoldKind::Mods => "mods",
                FoldKind::Block => "block",
                FoldKind::ArgList => "arglist",
                FoldKind::Region => "region",
                FoldKind::Consts => "consts",
                FoldKind::Statics => "statics"
            };
            assert_eq!(kind, &attr.unwrap());
        }
    }

    #[test]
    fn test_fold_comments() {
        check(
            r#"
<fold comment>// Hello
// this is a multiline
// comment
//</fold>

// But this is not

fn main() <fold block>{
    <fold comment>// We should
    // also
    // fold
    // this one.</fold>
    <fold comment>//! But this one is different
    //! because it has another flavor</fold>
    <fold comment>/* As does this
    multiline comment */</fold>
}</fold>"#,
        );
    }

    #[test]
    fn test_fold_imports() {
        check(
            r#"
use std::<fold block>{
    str,
    vec,
    io as iop
}</fold>;

fn main() <fold block>{
}</fold>"#,
        );
    }

    #[test]
    fn test_fold_mods() {
        check(
            r#"

pub mod foo;
<fold mods>mod after_pub;
mod after_pub_next;</fold>

<fold mods>mod before_pub;
mod before_pub_next;</fold>
pub mod bar;

mod not_folding_single;
pub mod foobar;
pub not_folding_single_next;

<fold mods>#[cfg(test)]
mod with_attribute;
mod with_attribute_next;</fold>

fn main() <fold block>{
}</fold>"#,
        );
    }

    #[test]
    fn test_fold_import_groups() {
        check(
            r#"
<fold imports>use std::str;
use std::vec;
use std::io as iop;</fold>

<fold imports>use std::mem;
use std::f64;</fold>

<fold imports>use std::collections::HashMap;
// Some random comment
use std::collections::VecDeque;</fold>

fn main() <fold block>{
}</fold>"#,
        );
    }

    #[test]
    fn test_fold_import_and_groups() {
        check(
            r#"
<fold imports>use std::str;
use std::vec;
use std::io as iop;</fold>

<fold imports>use std::mem;
use std::f64;</fold>

use std::collections::<fold block>{
    HashMap,
    VecDeque,
}</fold>;
// Some random comment

fn main() <fold block>{
}</fold>"#,
        );
    }

    #[test]
    fn test_folds_structs() {
        check(
            r#"
struct Foo <fold block>{
}</fold>
"#,
        );
    }

    #[test]
    fn test_folds_traits() {
        check(
            r#"
trait Foo <fold block>{
}</fold>
"#,
        );
    }

    #[test]
    fn test_folds_macros() {
        check(
            r#"
macro_rules! foo <fold block>{
    ($($tt:tt)*) => { $($tt)* }
}</fold>
"#,
        );
    }

    #[test]
    fn test_fold_match_arms() {
        check(
            r#"
fn main() <fold block>{
    match 0 <fold block>{
        0 => 0,
        _ => 1,
    }</fold>
}</fold>
"#,
        );
    }

    #[test]
    fn fold_big_calls() {
        check(
            r#"
fn main() <fold block>{
    frobnicate<fold arglist>(
        1,
        2,
        3,
    )</fold>
}</fold>
"#,
        )
    }

    #[test]
    fn fold_record_literals() {
        check(
            r#"
const _: S = S <fold block>{

}</fold>;
"#,
        )
    }

    #[test]
    fn fold_multiline_params() {
        check(
            r#"
fn foo<fold arglist>(
    x: i32,
    y: String,
)</fold> {}
"#,
        )
    }

    #[test]
    fn fold_region() {
        check(
            r#"
// 1. some normal comment
<fold region>// region: test
// 2. some normal comment
calling_function(x,y);
// endregion: test</fold>
"#,
        )
    }

    #[test]
    fn fold_consecutive_const() {
        check(
            r#"
<fold consts>const FIRST_CONST: &str = "first";
const SECOND_CONST: &str = "second";</fold>
            "#,
        )
    }

    #[test]
    fn fold_consecutive_static() {
        check(
            r#"
<fold statics>static FIRST_STATIC: &str = "first";
static SECOND_STATIC: &str = "second";</fold>
            "#,
        )
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate log;
#[macro_use]
extern crate failure;
extern crate serde_derive;
extern crate serde;
extern crate flexi_logger;
extern crate gen_lsp_server;
extern crate ra_lsp_server;

use serde::Deserialize;
use flexi_logger::{Duplicate, Logger};
use gen_lsp_server::{run_server, stdio_transport};
use ra_lsp_server::Result;

fn main() -> Result<()> {
    ::std::env::set_var("RUST_BACKTRACE", "short");
    Logger::with_env_or_str("error")
        .duplicate_to_stderr(Duplicate::All)
        .log_to_file()
        .directory("log")
        .start()?;
    info!("lifecycle: server started");
    match ::std::panic::catch_unwind(main_inner) {
        Ok(res) => {
            info!("lifecycle: terminating process with {:?}", res);
            res
        }
        Err(_) => {
            error!("server panicked");
            bail!("server panicked")
        }
    }
}

#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
struct InitializationOptions {
    publish_decorations: bool,
}

fn main_inner() -> Result<()> {
    let (receiver, sender, threads) = stdio_transport();
    let cwd = ::std::env::current_dir()?;
    run_server(
        ra_lsp_server::server_capabilities(),
        receiver,
        sender,
        |params, r, s| {
            let root = params
                .root_uri
                .and_then(|it| it.to_file_path().ok())
                .unwrap_or(cwd);
            let publish_decorations = params
                .initialization_options
                .and_then(|v| InitializationOptions::deserialize(v).ok())
                .map(|it| it.publish_decorations)
                == Some(true);
            ra_lsp_server::main_loop(false, root, publish_decorations, r, s)
        },
    )?;
    info!("shutting down IO...");
    threads.join()?;
    info!("... IO is down");
    Ok(())
}

/*
                    (let ((backend (eglot-xref-backend)))
                      (mapcar
                       (lambda (xref)
                         (let ((loc (xref-item-location xref)))
                           (propertize
                            (concat
                             (when (xref-file-location-p loc)
                               (with-slots (file line column) loc
                                 (format "%s:%s:%s:"
                                         (propertize (file-relative-name file)
                                                     'face 'compilation-info)
                                         (propertize (format "%s" line)
                                                     'face 'compilation-line
                                                     )
                                         column)))
                             (xref-item-summary xref))
                            'xref xref)))
                       (xref-backend-apropos backend "Analysis"))
                      )

*/
<commit_msg>Put derive back<commit_after>#[macro_use]
extern crate log;
#[macro_use]
extern crate failure;
#[macro_use]
extern crate serde_derive;
extern crate serde;
extern crate flexi_logger;
extern crate gen_lsp_server;
extern crate ra_lsp_server;

use serde::Deserialize;
use flexi_logger::{Duplicate, Logger};
use gen_lsp_server::{run_server, stdio_transport};
use ra_lsp_server::Result;

fn main() -> Result<()> {
    ::std::env::set_var("RUST_BACKTRACE", "short");
    Logger::with_env_or_str("error")
        .duplicate_to_stderr(Duplicate::All)
        .log_to_file()
        .directory("log")
        .start()?;
    info!("lifecycle: server started");
    match ::std::panic::catch_unwind(main_inner) {
        Ok(res) => {
            info!("lifecycle: terminating process with {:?}", res);
            res
        }
        Err(_) => {
            error!("server panicked");
            bail!("server panicked")
        }
    }
}

#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
struct InitializationOptions {
    publish_decorations: bool,
}

fn main_inner() -> Result<()> {
    let (receiver, sender, threads) = stdio_transport();
    let cwd = ::std::env::current_dir()?;
    run_server(
        ra_lsp_server::server_capabilities(),
        receiver,
        sender,
        |params, r, s| {
            let root = params
                .root_uri
                .and_then(|it| it.to_file_path().ok())
                .unwrap_or(cwd);
            let publish_decorations = params
                .initialization_options
                .and_then(|v| InitializationOptions::deserialize(v).ok())
                .map(|it| it.publish_decorations)
                == Some(true);
            ra_lsp_server::main_loop(false, root, publish_decorations, r, s)
        },
    )?;
    info!("shutting down IO...");
    threads.join()?;
    info!("... IO is down");
    Ok(())
}
<|endoftext|>


<commit_before>use super::super::interconnect;
use super::cp0;
use super::opcode::Opcode::*;
use super::opcode::SpecialOpcode::*;
use super::opcode::RegImmOpcode::*;
use super::instruction::Instruction;

use std::fmt;

const NUM_GPR: usize = 32;

pub struct Cpu {
    reg_gpr: [u64; NUM_GPR],
    reg_fpr: [f64; NUM_GPR],

    reg_pc: u64,

    reg_hi: u64,
    reg_lo: u64,

    reg_llbit: bool, // TODO: Enum type

    reg_fcr0: u32,
    reg_fcr31: u32,

    cp0: cp0::Cp0,

    interconnect: interconnect::Interconnect
}

impl Cpu {
    pub fn new(interconnect: interconnect::Interconnect) -> Cpu {
        Cpu {
            reg_gpr: [0; NUM_GPR],
            reg_fpr: [0.0; NUM_GPR],

            reg_pc: 0xffff_ffff_bfc0_0000, // TODO: Move to const

            reg_hi: 0,
            reg_lo: 0,

            reg_llbit: false,

            reg_fcr0: 0,
            reg_fcr31: 0,

            cp0: cp0::Cp0::default(),

            interconnect: interconnect
        }
    }

    // TODO: Different interface
    pub fn run(&mut self) {
        loop {
            self.run_instruction();
        }
    }

    pub fn run_instruction(&mut self) {
        let instr = self.read_instruction(self.reg_pc);

        self.print_instr(instr, self.reg_pc, false);

        self.reg_pc += 4;
        self.execute_instruction(instr);
    }

    fn read_instruction(&self, addr: u64) -> Instruction {
        Instruction(self.read_word(addr))
    }

    fn execute_instruction(&mut self, instr: Instruction) {
        match instr.opcode() {
            Special => {
                match instr.special_op() {
                    Sll => {
                        let value = self.read_reg_gpr(instr.rt()) << instr.sa();
                        let sign_extended_value = (value as i32) as u64;
                        self.write_reg_gpr(instr.rd() as usize, sign_extended_value);
                    }

                    Srl => {
                        let value = self.read_reg_gpr(instr.rt()) >> instr.sa();
                        let sign_extended_value = (value as i32) as u64;
                        self.write_reg_gpr(instr.rd() as usize, sign_extended_value);
                    }

                    Sllv => {
                        let shift = self.read_reg_gpr(instr.rs()) & 0b11111;
                        let value = self.read_reg_gpr(instr.rt()) << shift;
                        let sign_extended_value = (value as i32) as u64;
                        self.write_reg_gpr(instr.rd() as usize, sign_extended_value);
                    }

                    Srlv => {
                        let rs = self.read_reg_gpr(instr.rs()) as u32;
                        let rt = self.read_reg_gpr(instr.rt()) as u32;
                        let shift = rs & 0b11111;
                        let value = rt >> shift;
                        let sign_extended_value = (value as i32) as u64;
                        self.write_reg_gpr(instr.rd() as usize, sign_extended_value);
                    }

                    Jr => {
                        let delay_slot_pc = self.reg_pc;

                        // Update PC before executing delay slot instruction
                        self.reg_pc = self.read_reg_gpr(instr.rs());

                        self.execute_delay_slot(delay_slot_pc);
                    }

                    Multu => {
                        let rs = self.read_reg_gpr(instr.rs()) as u32;
                        let rt = self.read_reg_gpr(instr.rt()) as u32;

                        let res = (rs as u64) * (rt as u64);

                        // TODO: Undefined if last 2 instructions were
                        //  MFHI or MFLO
                        self.reg_lo = (res as i32) as u64;
                        self.reg_hi = ((res >> 32) as i32) as u64;
                    }

                    Mfhi => {
                        let value = self.reg_hi;
                        self.write_reg_gpr(instr.rd() as usize, value);
                    }

                    Mflo => {
                        let value = self.reg_lo;
                        self.write_reg_gpr(instr.rd() as usize, value);
                    }

                    Addu => {
                        let rs = self.read_reg_gpr(instr.rs());
                        let rt = self.read_reg_gpr(instr.rt());
                        let value = (rs.wrapping_add(rt) as i32) as u64;
                        self.write_reg_gpr(instr.rd() as usize, value);
                    }

                    Subu => {
                        let rs = self.read_reg_gpr(instr.rs());
                        let rt = self.read_reg_gpr(instr.rt());
                        let value = (rs.wrapping_sub(rt) as i32) as u64;
                        self.write_reg_gpr(instr.rd() as usize, value);
                    }

                    And => {
                        let rs = self.read_reg_gpr(instr.rs());
                        let rt = self.read_reg_gpr(instr.rt());
                        let value = rs & rt;
                        self.write_reg_gpr(instr.rd() as usize, value);
                    }

                    Or => {
                        let value = self.read_reg_gpr(instr.rs()) | self.read_reg_gpr(instr.rt());
                        self.write_reg_gpr(instr.rd() as usize, value);
                    }

                    Xor => {
                        let value = self.read_reg_gpr(instr.rs()) ^ self.read_reg_gpr(instr.rt());
                        self.write_reg_gpr(instr.rd() as usize, value);
                    }

                    Sltu => {
                        let rs = self.read_reg_gpr(instr.rs());
                        let rt = self.read_reg_gpr(instr.rt());
                        let value = if rs < rt { 1 } else { 0 };
                        self.write_reg_gpr(instr.rd() as usize, value);
                    }
                }
            }

            RegImm => {
                match instr.reg_imm_op() {
                    Bgezal => { self.branch(instr, true, |rs, _| (rs as i64) >= 0); }
                }
            }

            Addi => {
                // TODO: Handle exception overflow
                let res =
                    self.read_reg_gpr(instr.rs()) + instr.imm_sign_extended();
                self.write_reg_gpr(instr.rt(), res);
            }
            Addiu => {
                let res = self.read_reg_gpr(instr.rs())
                    .wrapping_add(instr.imm_sign_extended());
                self.write_reg_gpr(instr.rt(), res);
            }
            Andi => {
                let res = self.read_reg_gpr(instr.rs()) &
                    (instr.imm() as u64);
                self.write_reg_gpr(instr.rt(), res);
            }
            Ori => {
                let res = self.read_reg_gpr(instr.rs()) |
                    (instr.imm() as u64);
                self.write_reg_gpr(instr.rt(), res);
            }
            Lui => {
                let value = ((instr.imm() << 16) as i32) as u64;
                self.write_reg_gpr(instr.rt(), value);
            }
            Mtc0 => {
                let data = self.read_reg_gpr(instr.rt());
                self.cp0.write_reg(instr.rd(), data);
            }

            Beq => { self.branch(instr, false, |rs, rt| rs == rt); },
            Bne => { self.branch(instr, false, |rs, rt| rs != rt); },

            Beql => self.branch_likely(instr, |rs, rt| rs == rt),
            Bnel => self.branch_likely(instr, |rs, rt| rs != rt),

            Lw => {
                let base = instr.rs();

                let sign_extended_offset = instr.offset_sign_extended();
                let virt_addr =
                    self.read_reg_gpr(base).wrapping_add(sign_extended_offset);
                let mem = (self.read_word(virt_addr) as i32) as u64;
                self.write_reg_gpr(instr.rt(), mem);
            },

            Sw => {
                let base = instr.rs();

                let sign_extended_offset = instr.offset_sign_extended();
                let virt_addr =
                    self.read_reg_gpr(base).wrapping_add(sign_extended_offset);
                let mem = self.read_reg_gpr(instr.rt()) as u32;
                self.write_word(virt_addr, mem);
            }
        }
    }

    fn print_instr(&self, instr: Instruction, pc: u64, delay: bool) {
        print!("reg_pc {:018X}: ", pc);
        match instr.opcode() {
            Special => print!("Special: {:?}", instr.special_op()),
            RegImm => print!("RegImm: {:?}", instr.reg_imm_op()),
            _ => print!("{:?}", instr)
        }
        if delay {
            println!(" (DELAY)");
        } else {
            println!("");
        }
    }

    fn execute_delay_slot(&mut self, delay_slot_pc: u64) {
        let delay_slot_instr = self.read_instruction(delay_slot_pc);
        self.print_instr(delay_slot_instr, delay_slot_pc, true);
        self.execute_instruction(delay_slot_instr);
    }

    fn branch<F>(&mut self, instr: Instruction, write_link: bool, f: F) -> bool where F: FnOnce(u64, u64) -> bool {
        let rs = self.read_reg_gpr(instr.rs());
        let rt = self.read_reg_gpr(instr.rt());
        let is_taken = f(rs, rt);

        let delay_slot_pc = self.reg_pc;

        if write_link {
            let link_address = delay_slot_pc + 4;
            self.write_reg_gpr(31, link_address);
        }

        if is_taken {
            let sign_extended_offset =
                instr.offset_sign_extended() << 2;
            // Update PC before executing delay slot instruction
            self.reg_pc =
                self.reg_pc.wrapping_add(sign_extended_offset);

            self.execute_delay_slot(delay_slot_pc);
        }

        is_taken
    }

    fn branch_likely<F>(&mut self, instr: Instruction, f: F) where F: FnOnce(u64, u64) -> bool {
        if !self.branch(instr, false, f) {
            // Skip over delay slot instruction when not branching
            self.reg_pc = self.reg_pc.wrapping_add(4);
        }
    }

    fn read_word(&self, virt_addr: u64) -> u32 {
        let phys_addr = self.virt_addr_to_phys_addr(virt_addr);
        self.interconnect.read_word(phys_addr as u32)
    }

    fn write_word(&mut self, virt_addr: u64, value: u32) {
        let phys_addr = self.virt_addr_to_phys_addr(virt_addr);
        self.interconnect.write_word(phys_addr as u32, value);
    }

    fn virt_addr_to_phys_addr(&self, virt_addr: u64) -> u64 {
        // See Table 5-3 in the VR4300 User's Manual
        let addr_bit_values = (virt_addr >> 29) & 0b111;

        if addr_bit_values == 0b101 {
            // kseg1
            virt_addr - 0xffff_ffff_a000_0000
        } else {
            // TODO
            panic!("Unrecognized virtual address: {:#x}", virt_addr);
        }
    }

    fn write_reg_gpr(&mut self, index: usize, value: u64) {
        if index != 0 {
            self.reg_gpr[index] = value;
        }
    }

    fn read_reg_gpr(&self, index: usize) -> u64 {
        match index {
            0 => 0,
            _ => self.reg_gpr[index]
        }
    }
}

impl fmt::Debug for Cpu {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        const REGS_PER_LINE: usize = 2;
        const REG_NAMES: [&'static str; NUM_GPR] = [
        "r0", "at", "v0", "v1", "a0", "a1", "a2", "a3",
        "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
        "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
        "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra",
        ];

        try!(write!(f,"\nCPU General Purpose Registers:"));
        for reg_num in 0..NUM_GPR {
            if (reg_num % REGS_PER_LINE) == 0 {
                try!(writeln!(f,""));
            }
            try!(write!(f,
                "{reg_name}/gpr{num:02}: {value:#018X} ",
                num = reg_num,
                reg_name = REG_NAMES[reg_num],
                value = self.reg_gpr[reg_num],
            ));
        }

        try!(write!(f,"\n\nCPU Floating Point Registers:"));
        for reg_num in 0..NUM_GPR {
            if (reg_num % REGS_PER_LINE) == 0 {
                try!(writeln!(f,""));
            }
            try!(write!(f,
                "fpr{num:02}: {value:21} ",
                num = reg_num,
                value = self.reg_fpr[reg_num],)
            );
        }

        try!(writeln!(f,"\n\nCPU Special Registers:"));
        try!(writeln!(f,
            "\
            reg_pc: {:#018X}\n\
            reg_hi: {:#018X}\n\
            reg_lo: {:#018X}\n\
            reg_llbit: {}\n\
            reg_fcr0:  {:#010X}\n\
            reg_fcr31: {:#010X}\n\
            ",
            self.reg_pc,
            self.reg_hi,
            self.reg_lo,
            self.reg_llbit,
            self.reg_fcr0,
            self.reg_fcr31
        ));

        try!(writeln!(f, "{:#?}", self.cp0));
        writeln!(f, "{:#?}", self.interconnect)
    }
}
<commit_msg>Refactored instruction dispatch<commit_after>use super::super::interconnect;
use super::cp0;
use super::opcode::Opcode::*;
use super::opcode::SpecialOpcode::*;
use super::opcode::RegImmOpcode::*;
use super::instruction::Instruction;

use std::fmt;

const NUM_GPR: usize = 32;

enum SignExtendResult {
    Yes,
    No
}

enum WriteLink {
    Yes,
    No
}

enum DelaySlot {
    Yes,
    No
}

pub struct Cpu {
    reg_gpr: [u64; NUM_GPR],
    reg_fpr: [f64; NUM_GPR],

    reg_pc: u64,

    reg_hi: u64,
    reg_lo: u64,

    reg_llbit: bool, // TODO: Enum type

    reg_fcr0: u32,
    reg_fcr31: u32,

    cp0: cp0::Cp0,

    interconnect: interconnect::Interconnect
}

impl Cpu {
    pub fn new(interconnect: interconnect::Interconnect) -> Cpu {
        Cpu {
            reg_gpr: [0; NUM_GPR],
            reg_fpr: [0.0; NUM_GPR],

            reg_pc: 0xffff_ffff_bfc0_0000, // TODO: Move to const

            reg_hi: 0,
            reg_lo: 0,

            reg_llbit: false,

            reg_fcr0: 0,
            reg_fcr31: 0,

            cp0: cp0::Cp0::default(),

            interconnect: interconnect
        }
    }

    // TODO: Different interface
    pub fn run(&mut self) {
        loop {
            self.run_instruction();
        }
    }

    pub fn run_instruction(&mut self) {
        let instr = self.read_instruction(self.reg_pc);

        self.print_instr(instr, self.reg_pc, DelaySlot::No);

        self.reg_pc += 4;
        self.execute_instruction(instr);
    }

    fn read_instruction(&self, addr: u64) -> Instruction {
        Instruction(self.read_word(addr))
    }

    fn execute_instruction(&mut self, instr: Instruction) {
        match instr.opcode() {
            Special => {
                match instr.special_op() {
                    Sll => self.reg_instr(instr, |_, rt, sa| rt << sa),
                    Srl => self.reg_instr(instr, |_, rt, sa| {
                        let rt = rt as u32;
                        (rt >> sa) as u64
                    }),

                    Sllv =>
                        self.reg_instr(instr, |rs, rt, _| {
                            // TODO: Check to see if this is actually sa
                            let shift = rs & 0b11111;
                            rt << shift
                        }),

                    Srlv =>
                        self.reg_instr(instr, |rs, rt, _| {
                            let rs = rs as u32;
                            let rt = rt as u32;
                            let shift = rs & 0b11111;
                            (rt >> shift) as u64
                        }),

                    Jr => {
                        let delay_slot_pc = self.reg_pc;

                        // Update PC before executing delay slot instruction
                        self.reg_pc = self.read_reg_gpr(instr.rs());

                        self.execute_delay_slot(delay_slot_pc);
                    }

                    Multu => {
                        let rs = self.read_reg_gpr(instr.rs()) as u32;
                        let rt = self.read_reg_gpr(instr.rt()) as u32;

                        let res = (rs as u64) * (rt as u64);

                        // TODO: Undefined if last 2 instructions were
                        //  MFHI or MFLO
                        self.reg_lo = (res as i32) as u64;
                        self.reg_hi = ((res >> 32) as i32) as u64;
                    }

                    Mfhi => {
                        let value = self.reg_hi;
                        self.write_reg_gpr(instr.rd() as usize, value);
                    }
                    Mflo => {
                        let value = self.reg_lo;
                        self.write_reg_gpr(instr.rd() as usize, value);
                    }

                    Addu => self.reg_instr(instr, |rs, rt, _| rs.wrapping_add(rt)),
                    Subu => self.reg_instr(instr, |rs, rt, _| rs.wrapping_sub(rt)),

                    And => self.reg_instr(instr, |rs, rt, _| rs & rt),
                    Or => self.reg_instr(instr, |rs, rt, _| rs | rt),
                    Xor => self.reg_instr(instr, |rs, rt, _| rs ^ rt),

                    Sltu => self.reg_instr(instr, |rs, rt, _| if rs < rt { 1 } else { 0 })
                }
            }

            RegImm => {
                match instr.reg_imm_op() {
                    Bgezal => { self.branch(instr, WriteLink::Yes, |rs, _| (rs as i64) >= 0); }
                }
            }

            Addi =>
                self.imm_instr(instr, SignExtendResult::Yes, |rs, _, imm_sign_extended| {
                    // TODO: Handle overflow exception
                    rs + imm_sign_extended
                }),
            Addiu => self.imm_instr(instr, SignExtendResult::Yes, |rs, _, imm_sign_extended| rs.wrapping_add(imm_sign_extended)),

            Andi => self.imm_instr(instr, SignExtendResult::No, |rs, imm, _| rs & imm),
            Ori => self.imm_instr(instr, SignExtendResult::No, |rs, imm, _| rs | imm),

            Lui => self.imm_instr(instr, SignExtendResult::Yes, |_, imm, _| imm << 16),

            Mtc0 => {
                let data = self.read_reg_gpr(instr.rt());
                self.cp0.write_reg(instr.rd(), data);
            }

            Beq => { self.branch(instr, WriteLink::No, |rs, rt| rs == rt); },
            Bne => { self.branch(instr, WriteLink::No, |rs, rt| rs != rt); },

            Beql => self.branch_likely(instr, |rs, rt| rs == rt),
            Bnel => self.branch_likely(instr, |rs, rt| rs != rt),

            Lw => {
                let base = instr.rs();

                let sign_extended_offset = instr.offset_sign_extended();
                let virt_addr = self.read_reg_gpr(base).wrapping_add(sign_extended_offset);
                let mem = (self.read_word(virt_addr) as i32) as u64;
                self.write_reg_gpr(instr.rt(), mem);
            },

            Sw => {
                let base = instr.rs();

                let sign_extended_offset = instr.offset_sign_extended();
                let virt_addr = self.read_reg_gpr(base).wrapping_add(sign_extended_offset);
                let mem = self.read_reg_gpr(instr.rt()) as u32;
                self.write_word(virt_addr, mem);
            }
        }
    }

    fn imm_instr<F>(&mut self, instr: Instruction, sign_extend_result: SignExtendResult, f: F) where F: FnOnce(u64, u64, u64) -> u64 {
        let rs = self.read_reg_gpr(instr.rs());
        let imm = instr.imm() as u64;
        let imm_sign_extended = instr.imm_sign_extended();
        let value = f(rs, imm, imm_sign_extended);
        let sign_extended_value = (value as i32) as u64;
        let value = match sign_extend_result {
            SignExtendResult::Yes => sign_extended_value,
            _ => value
        };
        self.write_reg_gpr(instr.rt(), value);
    }

    fn reg_instr<F>(&mut self, instr: Instruction, f: F) where F: FnOnce(u64, u64, u32) -> u64 {
        let rs = self.read_reg_gpr(instr.rs());
        let rt = self.read_reg_gpr(instr.rt());
        let sa = instr.sa();
        let value = f(rs, rt, sa);
        let sign_extended_value = (value as i32) as u64;
        self.write_reg_gpr(instr.rd() as usize, sign_extended_value);
    }

    fn branch<F>(&mut self, instr: Instruction, write_link: WriteLink, f: F) -> bool where F: FnOnce(u64, u64) -> bool {
        let rs = self.read_reg_gpr(instr.rs());
        let rt = self.read_reg_gpr(instr.rt());
        let is_taken = f(rs, rt);

        let delay_slot_pc = self.reg_pc;

        if let WriteLink::Yes = write_link {
            let link_address = delay_slot_pc + 4;
            self.write_reg_gpr(31, link_address);
        }

        if is_taken {
            let sign_extended_offset = instr.offset_sign_extended() << 2;
            // Update PC before executing delay slot instruction
            self.reg_pc = self.reg_pc.wrapping_add(sign_extended_offset);

            self.execute_delay_slot(delay_slot_pc);
        }

        is_taken
    }

    fn branch_likely<F>(&mut self, instr: Instruction, f: F) where F: FnOnce(u64, u64) -> bool {
        if !self.branch(instr, WriteLink::No, f) {
            // Skip over delay slot instruction when not branching
            self.reg_pc = self.reg_pc.wrapping_add(4);
        }
    }

    fn print_instr(&self, instr: Instruction, pc: u64, delay_slot: DelaySlot) {
        print!("reg_pc {:018X}: ", pc);
        match instr.opcode() {
            Special => print!("Special: {:?}", instr.special_op()),
            RegImm => print!("RegImm: {:?}", instr.reg_imm_op()),
            _ => print!("{:?}", instr)
        }
        match delay_slot {
            DelaySlot::Yes => println!(" (DELAY)"),
            _ => println!("")
        };
    }

    fn execute_delay_slot(&mut self, delay_slot_pc: u64) {
        let delay_slot_instr = self.read_instruction(delay_slot_pc);
        self.print_instr(delay_slot_instr, delay_slot_pc, DelaySlot::Yes);
        self.execute_instruction(delay_slot_instr);
    }

    fn read_word(&self, virt_addr: u64) -> u32 {
        let phys_addr = self.virt_addr_to_phys_addr(virt_addr);
        self.interconnect.read_word(phys_addr as u32)
    }

    fn write_word(&mut self, virt_addr: u64, value: u32) {
        let phys_addr = self.virt_addr_to_phys_addr(virt_addr);
        self.interconnect.write_word(phys_addr as u32, value);
    }

    fn virt_addr_to_phys_addr(&self, virt_addr: u64) -> u64 {
        // See Table 5-3 in the VR4300 User's Manual
        let addr_bit_values = (virt_addr >> 29) & 0b111;

        if addr_bit_values == 0b101 {
            // kseg1
            virt_addr - 0xffff_ffff_a000_0000
        } else {
            // TODO
            panic!("Unrecognized virtual address: {:#x}", virt_addr);
        }
    }

    fn write_reg_gpr(&mut self, index: usize, value: u64) {
        if index != 0 {
            self.reg_gpr[index] = value;
        }
    }

    fn read_reg_gpr(&self, index: usize) -> u64 {
        match index {
            0 => 0,
            _ => self.reg_gpr[index]
        }
    }
}

impl fmt::Debug for Cpu {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        const REGS_PER_LINE: usize = 2;
        const REG_NAMES: [&'static str; NUM_GPR] = [
        "r0", "at", "v0", "v1", "a0", "a1", "a2", "a3",
        "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
        "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
        "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra",
        ];

        try!(write!(f,"\nCPU General Purpose Registers:"));
        for reg_num in 0..NUM_GPR {
            if (reg_num % REGS_PER_LINE) == 0 {
                try!(writeln!(f,""));
            }
            try!(write!(f,
                "{reg_name}/gpr{num:02}: {value:#018X} ",
                num = reg_num,
                reg_name = REG_NAMES[reg_num],
                value = self.reg_gpr[reg_num],
            ));
        }

        try!(write!(f,"\n\nCPU Floating Point Registers:"));
        for reg_num in 0..NUM_GPR {
            if (reg_num % REGS_PER_LINE) == 0 {
                try!(writeln!(f,""));
            }
            try!(write!(f,
                "fpr{num:02}: {value:21} ",
                num = reg_num,
                value = self.reg_fpr[reg_num],)
            );
        }

        try!(writeln!(f,"\n\nCPU Special Registers:"));
        try!(writeln!(f,
            "\
            reg_pc: {:#018X}\n\
            reg_hi: {:#018X}\n\
            reg_lo: {:#018X}\n\
            reg_llbit: {}\n\
            reg_fcr0:  {:#010X}\n\
            reg_fcr31: {:#010X}\n\
            ",
            self.reg_pc,
            self.reg_hi,
            self.reg_lo,
            self.reg_llbit,
            self.reg_fcr0,
            self.reg_fcr31
        ));

        try!(writeln!(f, "{:#?}", self.cp0));
        writeln!(f, "{:#?}", self.interconnect)
    }
}
<|endoftext|>


<commit_before>use super::super::{Grid, Coord};

#[derive(Clone, Copy)]
pub struct FieldShapeGrp {
    start: i32,
    end: i32,
    step: i32
}
impl Iterator for FieldShapeGrp {
    type Item = i32;
    fn next(&mut self) -> Option<i32> {
        let ret = self.start;
        self.start += self.step;

        if ret < self.end {
            Some(ret)
        } else {
            None
        }
    }
}
pub enum ClueLocation {
    Horizontal(i32),
    Vertical(i32)
}
pub struct FieldShape {
    pub has_clue: Grid<bool>,
    pub cell_to_groups: Grid<(i32, i32)>,
    pub group_to_cells: Vec<FieldShapeGrp>,
    pub clue_locations: Vec<ClueLocation>
}
impl FieldShape {
    fn new(has_clue: &Grid<bool>) -> FieldShape {
        let height = has_clue.height();
        let width = has_clue.width();
        let mut cell_to_groups = Grid::new(height, width, (-1, -1));
        let mut group_to_cells = vec![];
        let mut clue_locations = vec![];
        let mut current_grp_id = 0;

        // compute horizontal groups
        for y in 0..height {
            let mut start = -1;
            for x in 0..(width+1) {
                if x == width || has_clue[Coord { y: y, x: x }] {
                    if start != -1 {
                        group_to_cells.push(FieldShapeGrp {
                            start: start,
                            end: y * width + x,
                            step: 1
                        });
                        clue_locations.push(ClueLocation::Horizontal(start - 1));
                    }
                    start = -1;
                    current_grp_id += 1;
                } else {
                    if start == -1 {
                        start = y * width + x;
                    }
                    cell_to_groups[Coord { y: y, x: x }].0 = current_grp_id;
                }
            }
        }

        // compute vertical groups
        for x in 0..width {
            let mut start = -1;
            for y in 0..(height+1) {
                if y == height || has_clue[Coord { y: y, x: x }] {
                    if start != -1 {
                        group_to_cells.push(FieldShapeGrp {
                            start: start,
                            end: y * width + x,
                            step: width
                        });
                        clue_locations.push(ClueLocation::Vertical(start - width));
                    }
                    start = -1;
                    current_grp_id += 1;
                } else {
                    if start == -1 {
                        start = y * width + x;
                    }
                    cell_to_groups[Coord { y: y, x: x }].0 = current_grp_id;
                }
            }
        }

        FieldShape {
            has_clue: has_clue.clone(),
            cell_to_groups: cell_to_groups,
            group_to_cells: group_to_cells,
            clue_locations: clue_locations
        }
    }
}

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

    #[test]
    fn test_field_shape_grp() {
        {
            let mut n = 0;
            let mut sum = 0;
            let grp = FieldShapeGrp { start: 3, end: 6, step: 1 };
            for i in grp {
                n += 1;
                sum += i;
            }
            assert_eq!(n, 3);
            assert_eq!(sum, 3 + 4 + 5);
            assert_eq!(grp.start, 3);
        }
        {
            let mut n = 0;
            let mut sum = 0;
            let grp = FieldShapeGrp { start: 4, end: 16, step: 3 };
            for i in grp {
                n += 1;
                sum += i;
            }
            assert_eq!(n, 4);
            assert_eq!(sum, 4 + 7 + 10 + 13);
            assert_eq!(grp.start, 4);
        }
    }
}
<commit_msg>Kakuro: bug fix in FieldShape<commit_after>use super::super::{Grid, Coord};

#[derive(Clone, Copy)]
pub struct FieldShapeGrp {
    start: i32,
    end: i32,
    step: i32
}
impl Iterator for FieldShapeGrp {
    type Item = i32;
    fn next(&mut self) -> Option<i32> {
        let ret = self.start;
        self.start += self.step;

        if ret < self.end {
            Some(ret)
        } else {
            None
        }
    }
}
#[derive(Clone, Copy)]
pub enum ClueLocation {
    Horizontal(i32),
    Vertical(i32)
}
pub struct FieldShape {
    pub has_clue: Grid<bool>,
    pub cell_to_groups: Grid<(i32, i32)>,
    pub group_to_cells: Vec<FieldShapeGrp>,
    pub clue_locations: Vec<ClueLocation>
}
impl FieldShape {
    fn new(has_clue: &Grid<bool>) -> FieldShape {
        let height = has_clue.height();
        let width = has_clue.width();
        let mut cell_to_groups = Grid::new(height, width, (-1, -1));
        let mut group_to_cells = vec![];
        let mut clue_locations = vec![];
        let mut current_grp_id = 0;

        // compute horizontal groups
        for y in 0..height {
            let mut start = -1;
            for x in 0..(width+1) {
                if x == width || has_clue[Coord { y: y, x: x }] {
                    if start != -1 {
                        group_to_cells.push(FieldShapeGrp {
                            start: start,
                            end: y * width + x,
                            step: 1
                        });
                        clue_locations.push(ClueLocation::Horizontal(start - 1));
                        current_grp_id += 1;
                    }
                    start = -1;
                } else {
                    if start == -1 {
                        start = y * width + x;
                    }
                    cell_to_groups[Coord { y: y, x: x }].0 = current_grp_id;
                }
            }
        }

        // compute vertical groups
        for x in 0..width {
            let mut start = -1;
            for y in 0..(height+1) {
                if y == height || has_clue[Coord { y: y, x: x }] {
                    if start != -1 {
                        group_to_cells.push(FieldShapeGrp {
                            start: start,
                            end: y * width + x,
                            step: width
                        });
                        clue_locations.push(ClueLocation::Vertical(start - width));
                        current_grp_id += 1;
                    }
                    start = -1;
                } else {
                    if start == -1 {
                        start = y * width + x;
                    }
                    cell_to_groups[Coord { y: y, x: x }].1 = current_grp_id;
                }
            }
        }

        FieldShape {
            has_clue: has_clue.clone(),
            cell_to_groups: cell_to_groups,
            group_to_cells: group_to_cells,
            clue_locations: clue_locations
        }
    }
}

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

    #[test]
    fn test_field_shape_grp() {
        {
            let mut n = 0;
            let mut sum = 0;
            let grp = FieldShapeGrp { start: 3, end: 6, step: 1 };
            for i in grp {
                n += 1;
                sum += i;
            }
            assert_eq!(n, 3);
            assert_eq!(sum, 3 + 4 + 5);
            assert_eq!(grp.start, 3);
        }
        {
            let mut n = 0;
            let mut sum = 0;
            let grp = FieldShapeGrp { start: 4, end: 16, step: 3 };
            for i in grp {
                n += 1;
                sum += i;
            }
            assert_eq!(n, 4);
            assert_eq!(sum, 4 + 7 + 10 + 13);
            assert_eq!(grp.start, 4);
        }
    }
}
<|endoftext|>


<commit_before>use types::{Result, OscType, OscPacket, OscBundle, OscMessage};
use errors::OscError;
use utils;

use byteorder::{ByteOrder, BigEndian};
use std::iter;

pub fn encode(packet: &OscPacket) -> Result<Vec<u8>> {
    match *packet {
        OscPacket::Message(ref msg) => encode_message(msg),
        OscPacket::Bundle(ref bundle) => encode_bundle(bundle),
    }
}

pub fn encode_message(msg: &OscMessage) -> Result<Vec<u8>> {
    let mut msg_bytes: Vec<u8> = Vec::new();

    msg_bytes.extend(encode_string(&msg.addr));
    let mut type_tags: Vec<char> = vec![','];
    let mut arg_bytes: Vec<u8> = Vec::new();

    if msg.args.is_some() {
        let args = msg.args.as_ref().unwrap();
        // Possible optimization: write this as iterator
        for arg in args {
            let (bytes, tag): (Option<Vec<u8>>, char) = try!(encode_arg(arg));

            type_tags.push(tag);
            if bytes.is_some() {
                arg_bytes.extend(bytes.unwrap());
            }
        }
    }

    msg_bytes.extend(encode_string(&type_tags.iter()
                                             .cloned()
                                             .collect::<String>()));
    if arg_bytes.len() > 0 {
        msg_bytes.extend(arg_bytes);
    }
    Ok(msg_bytes)
}

fn encode_bundle(bundle: &OscBundle) -> Result<Vec<u8>> {
    let mut buf: Vec<u8> = Vec::new();
    buf.extend(encode_string(&"#bundle".to_string())
                   .iter()
                   .cloned());

    match try!(encode_arg(&bundle.timetag)) {
        (Some(x), _) => {
            buf.extend(x.iter().cloned());
        },
        (None, _) => {
            return Err(OscError::BadBundle("Missing time tag!".to_string()));
        }
    }

    for packet in &bundle.content {
        match packet {
            &OscPacket::Message(ref m) =>{
                let msg = try!(encode_message(m));
                let mut msg_size = vec![0u8; 4];
                BigEndian::write_u32(&mut msg_size, msg.len() as u32);
                buf.extend(msg_size.iter().chain(msg.iter()).cloned());
            }
            &OscPacket::Bundle(ref b) => {
                let bdl = try!(encode_bundle(b));
                let mut bdl_size = vec![0u8; 4];
                BigEndian::write_u32(&mut bdl_size, bdl.len() as u32);
                buf.extend(bdl_size.iter().chain(bdl.iter()).cloned());
            }
        }
    }

    Err(OscError::Unimplemented)
}

fn encode_arg(arg: &OscType) -> Result<(Option<Vec<u8>>, char)> {
    match arg {
        &OscType::Int(ref x) => {
            let mut bytes = vec![0u8; 4];
            BigEndian::write_i32(&mut bytes, *x);
            Ok((Some(bytes), 'i'))
        }
        &OscType::Long(ref x) => {
            let mut bytes = vec![0u8; 8];
            BigEndian::write_i64(&mut bytes, *x);
            Ok((Some(bytes), 'h'))
        }
        &OscType::Float(ref x) => {
            let mut bytes = vec![0u8; 4];
            BigEndian::write_f32(&mut bytes, *x);
            Ok((Some(bytes), 'f'))
        }
        &OscType::Double(ref x) => {
            let mut bytes = vec![0u8; 8];
            BigEndian::write_f64(&mut bytes, *x);
            Ok((Some(bytes), 'd'))
        }
        &OscType::Char(ref x) => {
            let mut bytes = vec![0u8; 4];
            BigEndian::write_u32(&mut bytes, *x as u32);
            Ok((Some(bytes), 'c'))
        }
        &OscType::String(ref x) => {
            Ok((Some(encode_string(&x)), 's'))
        }
        &OscType::Blob(ref x) => {
            // let mut bytes = x.clone();
            let padded_blob_length: usize = utils::pad(x.len() as u64) as usize;
            let mut bytes = vec![0u8; 4 + padded_blob_length];
            // write length
            BigEndian::write_i32(&mut bytes[..4], x.len() as i32);
            for (i, v) in x.iter().enumerate() {
                bytes[i + 4] = *v;
            }
            Ok((Some(bytes), 'b'))
        }
        &OscType::Time(ref x, ref y) => {
            Ok((Some(encode_time_tag(*x, *y)), 't'))
        }
        &OscType::Midi(ref x) => {
            Ok((Some(vec![x.port, x.status, x.data1, x.data2]), 'm'))
        }
        &OscType::Color(ref x) => {
            Ok((Some(vec![x.red, x.green, x.blue, x.alpha]), 'r'))
        }
        &OscType::Bool(ref x) => {
            if *x {
                Ok((None, 'T'))
            } else {
                Ok((None, 'F'))
            }
        }
        &OscType::Nil => {
            Ok((None, 'N'))
        }
        &OscType::Inf => {
            Ok((None, 'I'))
        }
        _ => Err(OscError::Unimplemented),
    }
}

fn encode_string(s: &String) -> Vec<u8> {
    let mut bytes: Vec<u8> = s.as_bytes()
                              .iter()
                              .cloned()
                              .chain(iter::once(0u8))
                              .collect();
    pad_bytes(&mut bytes);
    bytes
}

fn pad_bytes(bytes: &mut Vec<u8>) {
    let padded_lengh = utils::pad(bytes.len() as u64);
    while bytes.len() < padded_lengh as usize {
        bytes.push(0u8)
    }
}

fn encode_time_tag(sec: u32, frac: u32) -> Vec<u8> {
    let mut bytes = vec![0u8; 8];
    BigEndian::write_u32(&mut bytes[..4], sec);
    BigEndian::write_u32(&mut bytes[4..], frac);
    bytes
}
<commit_msg>Publicize `encode_bundle`<commit_after>use types::{Result, OscType, OscPacket, OscBundle, OscMessage};
use errors::OscError;
use utils;

use byteorder::{ByteOrder, BigEndian};
use std::iter;

pub fn encode(packet: &OscPacket) -> Result<Vec<u8>> {
    match *packet {
        OscPacket::Message(ref msg) => encode_message(msg),
        OscPacket::Bundle(ref bundle) => encode_bundle(bundle),
    }
}

pub fn encode_message(msg: &OscMessage) -> Result<Vec<u8>> {
    let mut msg_bytes: Vec<u8> = Vec::new();

    msg_bytes.extend(encode_string(&msg.addr));
    let mut type_tags: Vec<char> = vec![','];
    let mut arg_bytes: Vec<u8> = Vec::new();

    if msg.args.is_some() {
        let args = msg.args.as_ref().unwrap();
        // Possible optimization: write this as iterator
        for arg in args {
            let (bytes, tag): (Option<Vec<u8>>, char) = try!(encode_arg(arg));

            type_tags.push(tag);
            if bytes.is_some() {
                arg_bytes.extend(bytes.unwrap());
            }
        }
    }

    msg_bytes.extend(encode_string(&type_tags.iter()
                                             .cloned()
                                             .collect::<String>()));
    if arg_bytes.len() > 0 {
        msg_bytes.extend(arg_bytes);
    }
    Ok(msg_bytes)
}

    let mut buf: Vec<u8> = Vec::new();
    buf.extend(encode_string(&"#bundle".to_string())
                   .iter()
                   .cloned());
pub fn encode_bundle(bundle: &OscBundle) -> Result<Vec<u8>> {

    match try!(encode_arg(&bundle.timetag)) {
        (Some(x), _) => {
            buf.extend(x.iter().cloned());
        },
        (None, _) => {
            return Err(OscError::BadBundle("Missing time tag!".to_string()));
        }
    }

    for packet in &bundle.content {
        match packet {
            &OscPacket::Message(ref m) =>{
                let msg = try!(encode_message(m));
                let mut msg_size = vec![0u8; 4];
                BigEndian::write_u32(&mut msg_size, msg.len() as u32);
                buf.extend(msg_size.iter().chain(msg.iter()).cloned());
            }
            &OscPacket::Bundle(ref b) => {
                let bdl = try!(encode_bundle(b));
                let mut bdl_size = vec![0u8; 4];
                BigEndian::write_u32(&mut bdl_size, bdl.len() as u32);
                buf.extend(bdl_size.iter().chain(bdl.iter()).cloned());
            }
        }
    }

    Err(OscError::Unimplemented)
}

fn encode_arg(arg: &OscType) -> Result<(Option<Vec<u8>>, char)> {
    match arg {
        &OscType::Int(ref x) => {
            let mut bytes = vec![0u8; 4];
            BigEndian::write_i32(&mut bytes, *x);
            Ok((Some(bytes), 'i'))
        }
        &OscType::Long(ref x) => {
            let mut bytes = vec![0u8; 8];
            BigEndian::write_i64(&mut bytes, *x);
            Ok((Some(bytes), 'h'))
        }
        &OscType::Float(ref x) => {
            let mut bytes = vec![0u8; 4];
            BigEndian::write_f32(&mut bytes, *x);
            Ok((Some(bytes), 'f'))
        }
        &OscType::Double(ref x) => {
            let mut bytes = vec![0u8; 8];
            BigEndian::write_f64(&mut bytes, *x);
            Ok((Some(bytes), 'd'))
        }
        &OscType::Char(ref x) => {
            let mut bytes = vec![0u8; 4];
            BigEndian::write_u32(&mut bytes, *x as u32);
            Ok((Some(bytes), 'c'))
        }
        &OscType::String(ref x) => {
            Ok((Some(encode_string(&x)), 's'))
        }
        &OscType::Blob(ref x) => {
            // let mut bytes = x.clone();
            let padded_blob_length: usize = utils::pad(x.len() as u64) as usize;
            let mut bytes = vec![0u8; 4 + padded_blob_length];
            // write length
            BigEndian::write_i32(&mut bytes[..4], x.len() as i32);
            for (i, v) in x.iter().enumerate() {
                bytes[i + 4] = *v;
            }
            Ok((Some(bytes), 'b'))
        }
        &OscType::Time(ref x, ref y) => {
            Ok((Some(encode_time_tag(*x, *y)), 't'))
        }
        &OscType::Midi(ref x) => {
            Ok((Some(vec![x.port, x.status, x.data1, x.data2]), 'm'))
        }
        &OscType::Color(ref x) => {
            Ok((Some(vec![x.red, x.green, x.blue, x.alpha]), 'r'))
        }
        &OscType::Bool(ref x) => {
            if *x {
                Ok((None, 'T'))
            } else {
                Ok((None, 'F'))
            }
        }
        &OscType::Nil => {
            Ok((None, 'N'))
        }
        &OscType::Inf => {
            Ok((None, 'I'))
        }
        _ => Err(OscError::Unimplemented),
    }
}

fn encode_string(s: &String) -> Vec<u8> {
    let mut bytes: Vec<u8> = s.as_bytes()
                              .iter()
                              .cloned()
                              .chain(iter::once(0u8))
                              .collect();
    pad_bytes(&mut bytes);
    bytes
}

fn pad_bytes(bytes: &mut Vec<u8>) {
    let padded_lengh = utils::pad(bytes.len() as u64);
    while bytes.len() < padded_lengh as usize {
        bytes.push(0u8)
    }
}

fn encode_time_tag(sec: u32, frac: u32) -> Vec<u8> {
    let mut bytes = vec![0u8; 8];
    BigEndian::write_u32(&mut bytes[..4], sec);
    BigEndian::write_u32(&mut bytes[4..], frac);
    bytes
}
<|endoftext|>


<commit_before>#![feature(slicing_syntax)]

extern crate serialize;
extern crate erosion;

use std::io::net::ip::{
    Ipv4Addr,
    SocketAddr,
};

use serialize::base64::{MIME, ToBase64, FromBase64};

use erosion::membership::Membership;
use erosion::config;

static EROSION_ADDR_1: SocketAddr = SocketAddr {
    ip: Ipv4Addr(127, 0, 0, 1),
    port: 7201,
};
static EROSION_ADDR_2: SocketAddr = SocketAddr {
    ip: Ipv4Addr(127, 0, 0, 1),
    port: 7202,
};

fn bind() -> (int, Membership) {
    let mut config = config::local("node1".to_string());
    config.bind_addr = EROSION_ADDR_1;

    match Membership::bind(config.clone()) {
        Ok(membership) => (1, membership),
        Err(e) => {
            println!("{}", e);

            config.name = "node2".to_string();
            config.bind_addr = EROSION_ADDR_2;

            if let Ok(membership) = Membership::bind(config) {
                (2, membership)
            } else {
                panic!("couldn't bind socket.");
            }
        },
    }
}

fn ping(index: int, mut membership: Membership) {
    match index {
        1 => {
            membership.start();
        },
        _ => {
            membership.join("node1".to_string(), EROSION_ADDR_1);
        },
    }
}

fn main() {
    let msg = "hello,world";
    let encrypted = msg.as_bytes().to_base64(MIME);
    let plain = String::from_utf8(encrypted.from_base64().unwrap()).unwrap();

    println!("{}", encrypted);
    println!("{}", plain);

    let (index, membership) = bind();
    ping(index, membership);
}
<commit_msg>The client will auto set port<commit_after>#![feature(slicing_syntax)]

extern crate serialize;
extern crate erosion;

use std::io::net::ip::{
    Ipv4Addr,
    SocketAddr,
};

use serialize::base64::{MIME, ToBase64, FromBase64};

use erosion::membership::Membership;
use erosion::config;

static EROSION_ADDR: SocketAddr = SocketAddr {
    ip: Ipv4Addr(127, 0, 0, 1),
    port: 7201,
};

fn bind() -> (int, Membership) {
    let mut config = config::local("node1".to_string());
    let mut index = 1;
    config.bind_addr = EROSION_ADDR;

    loop {
        match Membership::bind(config.clone()) {
            Ok(membership) => return (index, membership),
            Err(e) => {
                println!("{}", e);

                index += 1;
                config.name = format!("node{}", index);
                config.bind_addr.port += 1;
            },
        };
    }
}

fn ping(index: int, mut membership: Membership) {
    match index {
        1 => {
            println!("First member, start!");
            membership.start();
        },
        _ => {
            println!("Join to {}", EROSION_ADDR);
            membership.join("node1".to_string(), EROSION_ADDR);
        },
    }
}

fn main() {
    let msg = "hello,world";
    let encrypted = msg.as_bytes().to_base64(MIME);
    let plain = String::from_utf8(encrypted.from_base64().unwrap()).unwrap();

    println!("{}", encrypted);
    println!("{}", plain);

    let (index, membership) = bind();
    ping(index, membership);
}
<|endoftext|>