<commit_before>// #![feature(scoped)]
// #![feature(collections)]

extern crate mmap;
extern crate time;
extern crate timely;
extern crate columnar;
extern crate dataflow_join;

extern crate docopt;
use docopt::Docopt;

use std::thread;

use dataflow_join::graph::{GraphTrait, GraphMMap};

use timely::progress::timestamp::RootTimestamp;
use timely::progress::scope::Scope;
use timely::progress::nested::Summary::Local;
use timely::example_static::*;
use timely::communication::*;
use timely::communication::pact::Exchange;

use timely::networking::initialize_networking;
use timely::networking::initialize_networking_from_file;

use timely::drain::DrainExt;

static USAGE: &'static str = "
Usage: pagerank <source> [options] [<arguments>...]

Options:
    -w <arg>, --workers <arg>    number of workers per process [default: 1]
    -p <arg>, --processid <arg>  identity of this process      [default: 0]
    -n <arg>, --processes <arg>  number of processes involved  [default: 1]
    -h <arg>, --hosts <arg>      list of host:port for workers
";

fn main () {
    let args = Docopt::new(USAGE).and_then(|dopt| dopt.parse()).unwrap_or_else(|e| e.exit());

    // let workers = if let Ok(threads) = args.get_str("<workers>").parse() { threads }
    //               else { panic!("invalid setting for workers: {}", args.get_str("<workers>")) };
    // println!("starting pagerank dataflow with {:?} worker{}", workers, if workers == 1 { "" } else { "s" });
    let source = args.get_str("<source>").to_owned();

    let workers: u64 = if let Ok(threads) = args.get_str("-w").parse() { threads }
                       else { panic!("invalid setting for --workers: {}", args.get_str("-t")) };
    let process_id: u64 = if let Ok(proc_id) = args.get_str("-p").parse() { proc_id }
                          else { panic!("invalid setting for --processid: {}", args.get_str("-p")) };
    let processes: u64 = if let Ok(processes) = args.get_str("-n").parse() { processes }
                         else { panic!("invalid setting for --processes: {}", args.get_str("-n")) };

    println!("Starting pagerank dataflow with");
    println!("\tworkers:\t{}", workers);
    println!("\tprocesses:\t{}", processes);
    println!("\tprocessid:\t{}", process_id);

    // vector holding communicators to use; one per local worker.
    if processes > 1 {
        println!("Initializing BinaryCommunicator");

        let hosts = args.get_str("-h");
        let communicators = if hosts != "" {
            initialize_networking_from_file(hosts, process_id, workers).ok().expect("error initializing networking")
        }
        else {
            let addresses = (0..processes).map(|index| format!("localhost:{}", 2101 + index).to_string()).collect();
            initialize_networking(addresses, process_id, workers).ok().expect("error initializing networking")
        };

        pagerank_multi(communicators, source);
    }
    else if workers > 1 {
        println!("Initializing ProcessCommunicator");
        pagerank_multi(ProcessCommunicator::new_vector(workers), source);
    }
    else {
        println!("Initializing ThreadCommunicator");
        pagerank_multi(vec![ThreadCommunicator], source);
    };
}

fn pagerank_multi<C>(communicators: Vec<C>, filename: String)
where C: Communicator+Send {
    let mut guards = Vec::new();
    let workers = communicators.len();
    for communicator in communicators.into_iter() {
        let filename = filename.clone();
        guards.push(thread::Builder::new().name(format!("timely worker {}", communicator.index()))
                                          .spawn(move || pagerank(communicator, filename, workers))
                                          .unwrap());
    }

    for guard in guards { guard.join().unwrap(); }
}

fn pagerank<C>(communicator: C, filename: String, workers: usize)
where C: Communicator {
    let index = communicator.index() as usize;
    let peers = communicator.peers() as usize;

    let mut root = GraphRoot::new(communicator);

    {   // new scope avoids long borrow on root
        let mut builder = root.new_subgraph();

        // establish the beginnings of a loop,
        // 20 iterations, each time around += 1.
        let (helper, stream) = builder.loop_variable::<(u32, f32)>(RootTimestamp::new(20), Local(1));

        let graph = GraphMMap::<u32>::new(&filename);

        let nodes = graph.nodes();

        let mut src = vec![1.0; 1 + (nodes / peers as usize)];  // local rank accumulation
        let mut dst = vec![0.0; nodes];                         // local rank accumulation

        let mut start = time::precise_time_s();

        // from feedback, place an operator that
        // aggregates and broadcasts ranks along edges.
        let ranks = stream.enable(builder).unary_notify(

            Exchange::new(|x: &(u32, f32)| x.0 as u64),     // 1. how data should be exchanged
            format!("PageRank"),                            // 2. a tasteful, descriptive name
            vec![RootTimestamp::new(0)],                    // 3. indicate an initial capability
            move |input, output, iterator| {                // 4. provide the operator logic

                while let Some((iter, _)) = iterator.next() {

                    // /---- should look familiar! ----\
                    for node in 0..src.len() {
                        src[node] = 0.15 + 0.85 * src[node];
                    }

                    for node in 0..src.len() {
                        let edges = graph.edges(index + peers * node);
                        let value = src[node] / edges.len() as f32;
                        for &b in edges {
                            dst[b as usize] += value;
                        }
                    }
                    // \------ end familiar part ------/

                    output.give_at(&iter, dst.drain_temp()
                                             .enumerate()
                                             .filter(|&(_,f)| f != 0.0)
                                             .map(|(u,f)| (u as u32, f)));

                    for _ in 0..(graph.nodes() + 1) { dst.push(0.0); }

                    println!("iteration {:?}: {}s", iter, time::precise_time_s() - start);
                    start = time::precise_time_s();
                }

                while let Some((iter, data)) = input.pull() {
                    iterator.notify_at(&iter);
                    for (node, rank) in data.drain_temp() {
                        src[node as usize / peers] += rank;
                    }
                }
            }
        );

        let local_index = index as usize % workers;

        let mut acc = vec![0.0; 1 + (nodes / workers)];

        ranks
        .unary_notify(
            Exchange::new(move |x: &(u32, f32)| (workers * (index / workers)) as u64 + (x.0 as u64 % workers as u64)),
            format!("Aggregation"),
            vec![],
            move |input, output, iterator| {
                while let Some((iter, data)) = input.pull() {
                    iterator.notify_at(&iter);
                    for (node, rank) in data.drain_temp() {
                        acc[node as usize / workers] += rank;
                    }
                }

                while let Some((item, _)) = iterator.next() {

                    output.give_at(&item, acc.drain_temp().enumerate().filter(|x| x.1 != 0.0)
                                             .map(|(u,f)| (((u * workers + local_index) as u32), f)));

                    for _ in 0..(1 + (nodes/workers)) { acc.push(0.0); }
                    assert!(acc.len() == (1 + (nodes/workers)));
                }
            }
        )
        .connect_loop(helper);
    }

    while root.step() { }
}
<commit_msg>less aggregation<commit_after>// #![feature(scoped)]
// #![feature(collections)]

extern crate mmap;
extern crate time;
extern crate timely;
extern crate columnar;
extern crate dataflow_join;

extern crate docopt;
use docopt::Docopt;

use std::thread;

use dataflow_join::graph::{GraphTrait, GraphMMap};

use timely::progress::timestamp::RootTimestamp;
use timely::progress::scope::Scope;
use timely::progress::nested::Summary::Local;
use timely::example_static::*;
use timely::communication::*;
use timely::communication::pact::Exchange;

use timely::networking::initialize_networking;
use timely::networking::initialize_networking_from_file;

use timely::drain::DrainExt;

static USAGE: &'static str = "
Usage: pagerank <source> [options] [<arguments>...]

Options:
    -w <arg>, --workers <arg>    number of workers per process [default: 1]
    -p <arg>, --processid <arg>  identity of this process      [default: 0]
    -n <arg>, --processes <arg>  number of processes involved  [default: 1]
    -h <arg>, --hosts <arg>      list of host:port for workers
";

fn main () {
    let args = Docopt::new(USAGE).and_then(|dopt| dopt.parse()).unwrap_or_else(|e| e.exit());

    // let workers = if let Ok(threads) = args.get_str("<workers>").parse() { threads }
    //               else { panic!("invalid setting for workers: {}", args.get_str("<workers>")) };
    // println!("starting pagerank dataflow with {:?} worker{}", workers, if workers == 1 { "" } else { "s" });
    let source = args.get_str("<source>").to_owned();

    let workers: u64 = if let Ok(threads) = args.get_str("-w").parse() { threads }
                       else { panic!("invalid setting for --workers: {}", args.get_str("-t")) };
    let process_id: u64 = if let Ok(proc_id) = args.get_str("-p").parse() { proc_id }
                          else { panic!("invalid setting for --processid: {}", args.get_str("-p")) };
    let processes: u64 = if let Ok(processes) = args.get_str("-n").parse() { processes }
                         else { panic!("invalid setting for --processes: {}", args.get_str("-n")) };

    println!("Starting pagerank dataflow with");
    println!("\tworkers:\t{}", workers);
    println!("\tprocesses:\t{}", processes);
    println!("\tprocessid:\t{}", process_id);

    // vector holding communicators to use; one per local worker.
    if processes > 1 {
        println!("Initializing BinaryCommunicator");

        let hosts = args.get_str("-h");
        let communicators = if hosts != "" {
            initialize_networking_from_file(hosts, process_id, workers).ok().expect("error initializing networking")
        }
        else {
            let addresses = (0..processes).map(|index| format!("localhost:{}", 2101 + index).to_string()).collect();
            initialize_networking(addresses, process_id, workers).ok().expect("error initializing networking")
        };

        pagerank_multi(communicators, source);
    }
    else if workers > 1 {
        println!("Initializing ProcessCommunicator");
        pagerank_multi(ProcessCommunicator::new_vector(workers), source);
    }
    else {
        println!("Initializing ThreadCommunicator");
        pagerank_multi(vec![ThreadCommunicator], source);
    };
}

fn pagerank_multi<C>(communicators: Vec<C>, filename: String)
where C: Communicator+Send {
    let mut guards = Vec::new();
    let workers = communicators.len();
    for communicator in communicators.into_iter() {
        let filename = filename.clone();
        guards.push(thread::Builder::new().name(format!("timely worker {}", communicator.index()))
                                          .spawn(move || pagerank(communicator, filename, workers))
                                          .unwrap());
    }

    for guard in guards { guard.join().unwrap(); }
}

fn pagerank<C>(communicator: C, filename: String, workers: usize)
where C: Communicator {
    let index = communicator.index() as usize;
    let peers = communicator.peers() as usize;

    let mut root = GraphRoot::new(communicator);

    {   // new scope avoids long borrow on root
        let mut builder = root.new_subgraph();

        // establish the beginnings of a loop,
        // 20 iterations, each time around += 1.
        let (helper, stream) = builder.loop_variable::<(u32, f32)>(RootTimestamp::new(20), Local(1));

        let graph = GraphMMap::<u32>::new(&filename);

        let nodes = graph.nodes();

        let mut src = vec![1.0; 1 + (nodes / peers as usize)];  // local rank accumulation
        let mut dst = vec![0.0; nodes];                         // local rank accumulation

        let mut start = time::precise_time_s();

        // from feedback, place an operator that
        // aggregates and broadcasts ranks along edges.
        let ranks = stream.enable(builder).unary_notify(

            Exchange::new(|x: &(u32, f32)| x.0 as u64),     // 1. how data should be exchanged
            format!("PageRank"),                            // 2. a tasteful, descriptive name
            vec![RootTimestamp::new(0)],                    // 3. indicate an initial capability
            move |input, output, iterator| {                // 4. provide the operator logic

                while let Some((iter, _)) = iterator.next() {

                    // /---- should look familiar! ----\
                    for node in 0..src.len() {
                        src[node] = 0.15 + 0.85 * src[node];
                    }

                    for node in 0..src.len() {
                        let edges = graph.edges(index + peers * node);
                        let value = src[node] / edges.len() as f32;
                        for &b in edges {
                            dst[b as usize] += value;
                        }
                    }
                    // \------ end familiar part ------/

                    output.give_at(&iter, dst.drain_temp()
                                             .enumerate()
                                             .filter(|&(_,f)| f != 0.0)
                                             .map(|(u,f)| (u as u32, f)));

                    for _ in 0..(graph.nodes() + 1) { dst.push(0.0); }

                    println!("iteration {:?}: {}s", iter, time::precise_time_s() - start);
                    start = time::precise_time_s();
                }

                while let Some((iter, data)) = input.pull() {
                    iterator.notify_at(&iter);
                    for (node, rank) in data.drain_temp() {
                        src[node as usize / peers] += rank;
                    }
                }
            }
        );

        let local_index = index as usize % workers;

        let mut acc = vec![0.0; 1 + (nodes / workers)];

        ranks
        // .unary_notify(
        //     Exchange::new(move |x: &(u32, f32)| (workers * (index / workers)) as u64 + (x.0 as u64 % workers as u64)),
        //     format!("Aggregation"),
        //     vec![],
        //     move |input, output, iterator| {
        //         while let Some((iter, data)) = input.pull() {
        //             iterator.notify_at(&iter);
        //             for (node, rank) in data.drain_temp() {
        //                 acc[node as usize / workers] += rank;
        //             }
        //         }
        //
        //         while let Some((item, _)) = iterator.next() {
        //
        //             output.give_at(&item, acc.drain_temp().enumerate().filter(|x| x.1 != 0.0)
        //                                      .map(|(u,f)| (((u * workers + local_index) as u32), f)));
        //
        //             for _ in 0..(1 + (nodes/workers)) { acc.push(0.0); }
        //             assert!(acc.len() == (1 + (nodes/workers)));
        //         }
        //     }
        // )
        .connect_loop(helper);
    }

    while root.step() { }
}
<|endoftext|>


<commit_before>use std::io::println;
use rf_common::*;
use syntax::ast;
use syntax::codemap::Pos;
use find_ast_node::FNodeInfoMap;
use jumptodefmap::{JumpToDefMap};
use codemaput::ToZTextFilePos;
use ioutil;
use rfindctx::{RFindCtx, str_of_opt_ident};

/*new file*/

pub type ZeroBasedIndex=uint;

/// cross crate map, extra info written out when compiling links of a crate
/// allows sunsequent crates to jump to definitions in that crate
/// TODO - check if this already exists in the 'cstore/create metadata'
/// specificially we need node->span info
#[deriving(Clone)]
pub struct CrossCrateMapItem {
    fname:~str,
    line:ZeroBasedIndex,
    col:uint,
    len:uint
}

pub type CrossCrateMap = HashMap<ast::DefId,CrossCrateMapItem>;

pub fn read_cross_crate_map(_:&RFindCtx, crate_num:int, crate_name:&str,lib_path:&str)->~CrossCrateMap {
    let mut raw_bytes=ioutil::fileLoad(crate_name);
    if raw_bytes.len()==0 {
        println("loading lib crosscratemap "+lib_path+"/"+crate_name);
        raw_bytes=ioutil::fileLoad(lib_path+"/"+crate_name);
		if raw_bytes.len()<=0 {
			println("must run rustfind in library directories if you want links to work (needs html & .rfx files)\n"
		}
    }
    let rfx=str::from_utf8(raw_bytes);
    println("loaded cratemap "+rfx.get_ref().len().to_str()+" bytes"+" as crate "+crate_num.to_str());
//  for &x in raw_bytes.iter() { rfx.push_char(x as char); }

    let mut xcm=~HashMap::new();
    for s in rfx.get_ref().lines() {
//      println(s.to_str());
        let toks=s.split('\t').collect::<~[&str]>();
        if toks.len()>=6 {
            match toks[0] {
                "jdef"=> {
                    // jimp- to def info, we dont need this here as we already generated it
                    // for the current crate. TODO , genarlized rfx would use it..
                }
                "node"=> {
                    // node cratename nodeid parentid sourcefile line col len type [ident]
                    //cratename is ignoredd, because we already know it.
                    // parent id ignored, we use span information to reconstruct AST

                    let node_id: int= from_str::<int>(toks[2]).unwrap_or(0);
                    xcm.insert(ast::DefId{krate:crate_num as u32, node:node_id as u32,},
                        CrossCrateMapItem{
                            fname:  toks[4].to_owned(),
                            line:   from_str(toks[5]).unwrap_or(0)-1,
                            col:    from_str(toks[6]).unwrap_or(0),
                            len:    from_str(toks[7]).unwrap_or(0)
                        }
                    );
                }
                // legacy noode definitons,no keyword
                _=>{

                    let node_id:int=from_str(toks[1]).unwrap_or(0);
                    xcm.insert(ast::DefId{krate:crate_num as u32, node:node_id as u32,},
                        CrossCrateMapItem{
                            fname:  toks[2].to_owned(),
                            line:   from_str(toks[3]).unwrap_or(0)-1,
                            col:    from_str(toks[4]).unwrap_or(0),
                            len:    from_str(toks[5]).unwrap_or(0)
                        }
                    );
                }
            }
        }
    }
    //dump!(xcm);
    println("from cratemap "+rfx.get_ref().len().to_str()+" bytes");
    xcm
}

pub fn write_cross_crate_map(dc:&RFindCtx, _:&str,nim:&FNodeInfoMap, _:&HashMap<ast::NodeId, ast::DefId>, jdm:&JumpToDefMap) {
    // write inter-crate node map
    let crate_rel_path_name= dc.codemap().files.borrow();
    let crate_rel_path_name = Path::new(crate_rel_path_name.get(0).name.as_slice());
    let new_format:bool=true;

    let curr_crate_name_only = crate_rel_path_name.filestem_str().unwrap_or("");
    println!("Writing rustfind cross-crate link info for {}", curr_crate_name_only);
    let out_path = crate_rel_path_name.with_extension("rfx");
    let out = ioutil::file_create_with_dirs(&out_path).map(|out| {
        let mut out_file = out;
        // todo - idents to a seperate block, they're rare.
        for (k,ni) in nim.iter() {
            match ni.span.lo.to_text_file_pos(dc.tycx_ref()) {
                Some(tfp)=>{
                    // new format, a little more verbose,
                    // and includes parent id for easier reconstruction of full AST
                    // "node" cratename id parent_id filename line col len type [ident]
                    if new_format {
                        try!(writeln!(&mut out_file, "node\t{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}",
                            curr_crate_name_only, k, ni.parent_id, tfp.name, (tfp.line + 1), tfp.col,
                            (ni.span.hi - ni.span.lo).to_uint(), ni.kind, str_of_opt_ident(ni.ident)));
                    } else  {
                        // old format, relies on spans to reconstruct AST.
                        // cratename id filename line col len type [ident]
                        try!(writeln!(&mut out_file, "{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}",
                            curr_crate_name_only, k, tfp.name, (tfp.line+1), tfp.col,
                            (ni.span.hi-ni.span.lo).to_uint(), ni.kind, str_of_opt_ident(ni.ident)));
                    }
                },
                None=>{}
            }
        }

        for (k,v) in jdm.iter()  {
            let cname: ~str = if v.krate > 0 {
                dc.cstore().get_crate_data(v.krate).name.to_str()
            } else {
                curr_crate_name_only.to_str()
            };
            //println(cdata.name);
            try!(writeln!(&mut out_file, "jdef\t{}\t{}\t{}", k, cname, v.node));
        }

        Ok(())
    });

    match out {
        Err(e) => println!("Error while writing to {}: {}", out_path.display(), e),
        _ => ()
    };

//  for (k,v) in ndm.iter()  {
//      outp.push_str("def\t"+k.to_str()+"\t"+dc.tycx.cstore.crate() +v.node.to_str()+"\n");
//  }
}
<commit_msg>sane defaults: sourcestyle is now embedded and auto copied, no faffing around with the tool needing to find resources; and /home/walter/gplsrc/rust is used if you dont specify the library directory<commit_after>use std::io::println;
use rf_common::*;
use syntax::ast;
use syntax::codemap::Pos;
use find_ast_node::FNodeInfoMap;
use jumptodefmap::{JumpToDefMap};
use codemaput::ToZTextFilePos;
use ioutil;
use rfindctx::{RFindCtx, str_of_opt_ident};

/*new file*/

pub type ZeroBasedIndex=uint;

/// cross crate map, extra info written out when compiling links of a crate
/// allows sunsequent crates to jump to definitions in that crate
/// TODO - check if this already exists in the 'cstore/create metadata'
/// specificially we need node->span info
#[deriving(Clone)]
pub struct CrossCrateMapItem {
    fname:~str,
    line:ZeroBasedIndex,
    col:uint,
    len:uint
}

pub type CrossCrateMap = HashMap<ast::DefId,CrossCrateMapItem>;

pub fn read_cross_crate_map(_:&RFindCtx, crate_num:int, crate_name:&str,lib_path:&str)->~CrossCrateMap {
    let mut raw_bytes=ioutil::fileLoad(crate_name);
    if raw_bytes.len()==0 {
        println("loading lib crosscratemap "+lib_path+"/"+crate_name);
        raw_bytes=ioutil::fileLoad(lib_path+"/"+crate_name);
		if raw_bytes.len()<=0 {
			println("must run rustfind in library directories if you want links to work (needs html & .rfx files)\n");
		}
    }
    let rfx=str::from_utf8(raw_bytes);
    println("loaded cratemap "+rfx.get_ref().len().to_str()+" bytes"+" as crate "+crate_num.to_str());
//  for &x in raw_bytes.iter() { rfx.push_char(x as char); }

    let mut xcm=~HashMap::new();
    for s in rfx.get_ref().lines() {
//      println(s.to_str());
        let toks=s.split('\t').collect::<~[&str]>();
        if toks.len()>=6 {
            match toks[0] {
                "jdef"=> {
                    // jimp- to def info, we dont need this here as we already generated it
                    // for the current crate. TODO , genarlized rfx would use it..
                }
                "node"=> {
                    // node cratename nodeid parentid sourcefile line col len type [ident]
                    //cratename is ignoredd, because we already know it.
                    // parent id ignored, we use span information to reconstruct AST

                    let node_id: int= from_str::<int>(toks[2]).unwrap_or(0);
                    xcm.insert(ast::DefId{krate:crate_num as u32, node:node_id as u32,},
                        CrossCrateMapItem{
                            fname:  toks[4].to_owned(),
                            line:   from_str(toks[5]).unwrap_or(0)-1,
                            col:    from_str(toks[6]).unwrap_or(0),
                            len:    from_str(toks[7]).unwrap_or(0)
                        }
                    );
                }
                // legacy noode definitons,no keyword
                _=>{

                    let node_id:int=from_str(toks[1]).unwrap_or(0);
                    xcm.insert(ast::DefId{krate:crate_num as u32, node:node_id as u32,},
                        CrossCrateMapItem{
                            fname:  toks[2].to_owned(),
                            line:   from_str(toks[3]).unwrap_or(0)-1,
                            col:    from_str(toks[4]).unwrap_or(0),
                            len:    from_str(toks[5]).unwrap_or(0)
                        }
                    );
                }
            }
        }
    }
    //dump!(xcm);
    println("from cratemap "+rfx.get_ref().len().to_str()+" bytes");
    xcm
}

pub fn write_cross_crate_map(dc:&RFindCtx, _:&str,nim:&FNodeInfoMap, _:&HashMap<ast::NodeId, ast::DefId>, jdm:&JumpToDefMap) {
    // write inter-crate node map
    let crate_rel_path_name= dc.codemap().files.borrow();
    let crate_rel_path_name = Path::new(crate_rel_path_name.get(0).name.as_slice());
    let new_format:bool=true;

    let curr_crate_name_only = crate_rel_path_name.filestem_str().unwrap_or("");
    println!("Writing rustfind cross-crate link info for {}", curr_crate_name_only);
    let out_path = crate_rel_path_name.with_extension("rfx");
    let out = ioutil::file_create_with_dirs(&out_path).map(|out| {
        let mut out_file = out;
        // todo - idents to a seperate block, they're rare.
        for (k,ni) in nim.iter() {
            match ni.span.lo.to_text_file_pos(dc.tycx_ref()) {
                Some(tfp)=>{
                    // new format, a little more verbose,
                    // and includes parent id for easier reconstruction of full AST
                    // "node" cratename id parent_id filename line col len type [ident]
                    if new_format {
                        try!(writeln!(&mut out_file, "node\t{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}",
                            curr_crate_name_only, k, ni.parent_id, tfp.name, (tfp.line + 1), tfp.col,
                            (ni.span.hi - ni.span.lo).to_uint(), ni.kind, str_of_opt_ident(ni.ident)));
                    } else  {
                        // old format, relies on spans to reconstruct AST.
                        // cratename id filename line col len type [ident]
                        try!(writeln!(&mut out_file, "{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}",
                            curr_crate_name_only, k, tfp.name, (tfp.line+1), tfp.col,
                            (ni.span.hi-ni.span.lo).to_uint(), ni.kind, str_of_opt_ident(ni.ident)));
                    }
                },
                None=>{}
            }
        }

        for (k,v) in jdm.iter()  {
            let cname: ~str = if v.krate > 0 {
                dc.cstore().get_crate_data(v.krate).name.to_str()
            } else {
                curr_crate_name_only.to_str()
            };
            //println(cdata.name);
            try!(writeln!(&mut out_file, "jdef\t{}\t{}\t{}", k, cname, v.node));
        }

        Ok(())
    });

    match out {
        Err(e) => println!("Error while writing to {}: {}", out_path.display(), e),
        _ => ()
    };

//  for (k,v) in ndm.iter()  {
//      outp.push_str("def\t"+k.to_str()+"\t"+dc.tycx.cstore.crate() +v.node.to_str()+"\n");
//  }
}
<|endoftext|>


<commit_before>use std::thread::Thread;
use std::io::timer;
use std::time::duration::Duration;

static NTHREADS: int = 10;

// This is the `main` thread
fn main() {
    for i in range(0, NTHREADS) {
        // Spin up another thread
        Thread::spawn(move || {
            println!("this is thread number {}", i)
        }).detach();
    }

    // Wait for threads to complete
    let interval = Duration::milliseconds(1000);
    timer::sleep(interval);
}
<commit_msg>threads: join threads instead of sleeping<commit_after>use std::thread::Thread;

static NTHREADS: int = 10;

// This is the `main` thread
fn main() {
    for i in range(0, NTHREADS) {
        // Spin up another thread
        let _ = Thread::spawn(move || {
            println!("this is thread number {}", i)
        }).join();
    }
}
<|endoftext|>


<commit_before>#[feature(struct_variant)];
#[feature(globs)];
#[link(name = "nss", vers = "0.0")]
extern mod nspr;

extern mod extra;

use std::os;
use std::ptr;
use std::rt::io::{Reader, Writer};
use std::rt::io::net::ip::{SocketAddr, IpAddr, Ipv4Addr};
pub use raw::nss::*;
use nspr::raw::nspr::*;
use std::libc::{c_void};
use std::vec;
use extra::sync::Mutex;

#[cfg(test)]
mod tests;

pub mod raw { pub mod nss; }

pub struct NSS {

    nss_ctx: Option<*c_void>,
    nss_cert_mod: Option<SECMODModule>,
    nss_mutex: Mutex,
}

impl NSS {

pub fn new() -> NSS {
 NSS { nss_ctx: None, nss_cert_mod: None, nss_mutex: Mutex::new() }
}

pub fn init(&mut self) -> SECStatus {
  let no_nss =
  do self.nss_mutex.lock {
     self.nss_ctx.is_none()
  };
  if(!no_nss) { return SECSuccess; }
  let dir = format!("sql:{}/.pki/nssdb", os::getenv("HOME").unwrap_or(~"")).to_owned();
  dir.with_c_str(|nssdb| self.nss_ctx = Some(unsafe { NSS_InitContext(nssdb, ptr::null(), ptr::null(), ptr::null(), ptr::null(), NSS_INIT_READONLY | NSS_INIT_PK11RELOAD) }));
  info!("Error {}", unsafe { std::str::raw::from_c_str(PR_ErrorToName(PR_GetError())) } );
  unsafe{  NSS_SetDomesticPolicy() };
  self.nss_cert_mod = Some(unsafe { *SECMOD_LoadUserModule("library=libnssckbi.so name=\"Root Certs\"".to_c_str().unwrap(),  ptr::null(), PRFalse)});
  if(self.nss_cert_mod.unwrap().loaded != PRTrue)
  {
     return SECFailure;
  }

SECSuccess
}

pub fn uninit(&mut self) -> SECStatus {
    if(self.nss_ctx.is_none()) { return SECSuccess; }
    unsafe {
    SECMOD_DestroyModule(&self.nss_cert_mod.unwrap());
    NSS_ShutdownContext(self.nss_ctx.unwrap());
    }
    self.nss_ctx = None;
    SECSuccess
}

}

pub fn ssl_connect(addr: SocketAddr, hostname: ~str) -> SSLStream
{
    unsafe {

    let oldmodel = PR_OpenTCPSocket(PR_AF_INET);
    let model = SSL_ImportFD(ptr::null(), oldmodel);
    do nss_cmd { SSL_OptionSet(model, SSL_ENABLE_SSL2, PRFalse) };
    do nss_cmd { SSL_OptionSet(model, SSL_V2_COMPATIBLE_HELLO, PRFalse) };
    do nss_cmd { SSL_OptionSet(model, SSL_ENABLE_DEFLATE, PRFalse) };
    let sslfd = PR_OpenTCPSocket(PR_AF_INET);
    PR_Connect(sslfd, &PRNetAddr { family: PR_AF_INET, ip: PR_htonl(IpAddrToBytes(addr.ip)), port: PR_htons(addr.port), pad: [0,0,0,0,0,0,0,0] }, 30000);
    let ssl_socket = SSL_ImportFD(model, sslfd);
    PR_Close(model);
    do nss_cmd { SSL_ResetHandshake(ssl_socket, PRFalse) };
    do nss_cmd { SSL_SetURL(ssl_socket, hostname.to_c_str().unwrap()) };
    do nss_cmd { SSL_ForceHandshake(ssl_socket) };

    SSLStream { sslfd: ssl_socket, is_eof: false }

    }
}

pub fn nss_cmd(blk: &fn() -> SECStatus) {
    let result = blk();
    if(result == SECFailure) {
      fail!("NSS Failed with {}", unsafe { std::str::raw::from_c_str(PR_ErrorToName(PR_GetError())) });
    }
}

pub struct SSLStream {
    sslfd: *c_void,
    is_eof: bool,
}

impl Reader for SSLStream {
    fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
    match unsafe { PR_Read(self.sslfd, vec::raw::to_ptr(buf) as *c_void, buf.len() as i32) } {
     0 => { self.is_eof = true; None },
     -1 => None,
     bytes_read => Some(bytes_read as uint)
    }
}
       fn eof(&mut self) -> bool {
            self.is_eof
       }
}

impl Writer for SSLStream {
    fn write(&mut self, buf: &[u8]) {
        unsafe { PR_Write(self.sslfd, vec::raw::to_ptr(buf) as *c_void, buf.len() as i32) };
    }
    fn flush(&mut self) {
        //nop
    }
}

pub fn IpAddrToBytes(addr: IpAddr) -> u32 {
match addr {
        Ipv4Addr(o1, o2, o3, o4) => ((o1 as u32 << 24) + (o2 as u32 << 16) + (o3 as u32 << 8) + (o4 as u32 << 0)) as u32,
        _ => 0u32 }
}

<commit_msg>This synchronization seems to work better<commit_after>#[feature(struct_variant)];
#[feature(globs)];
#[link(name = "nss", vers = "0.0")]
extern mod nspr;

extern mod extra;

use std::os;
use std::ptr;
use std::rt::io::{Reader, Writer};
use std::rt::io::net::ip::{SocketAddr, IpAddr, Ipv4Addr};
pub use raw::nss::*;
use nspr::raw::nspr::*;
use std::libc::{c_void};
use std::vec;
use extra::sync::RWLock;

#[cfg(test)]
mod tests;

pub mod raw { pub mod nss; }

pub struct NSS {

    nss_ctx: Option<*c_void>,
    nss_cert_mod: Option<SECMODModule>,
}

impl NSS {

pub fn new() -> NSS {
 NSS { nss_ctx: None, nss_cert_mod: None  }
}

pub fn init(&mut self) -> SECStatus {
  let lock = RWLock::new();
  let no_nss = do lock.write { self.nss_ctx.is_none() };

  if(!no_nss) { return SECSuccess; }

  let dir = format!("sql:{}/.pki/nssdb", os::getenv("HOME").unwrap_or(~"")).to_owned();
  dir.with_c_str(|nssdb| self.nss_ctx = Some(unsafe { NSS_InitContext(nssdb, ptr::null(), ptr::null(), ptr::null(), ptr::null(), NSS_INIT_READONLY | NSS_INIT_PK11RELOAD) }));
   do nss_cmd {  unsafe { NSS_SetDomesticPolicy() } };
  self.nss_cert_mod = Some(unsafe { *SECMOD_LoadUserModule("library=libnssckbi.so name=\"Root Certs\"".to_c_str().unwrap(),  ptr::null(), PRFalse)});
  if(self.nss_cert_mod.unwrap().loaded != PRTrue)
  {
     return SECFailure;
  }

SECSuccess
}

pub fn uninit(&mut self) -> SECStatus {
    let lock = RWLock::new();
    let no_nss = do lock.write { self.nss_ctx.is_none() };
    if(no_nss) { return SECSuccess; }
    unsafe {
    SECMOD_DestroyModule(&self.nss_cert_mod.unwrap());
    NSS_ShutdownContext(self.nss_ctx.unwrap());
    }
    self.nss_ctx = None;
    SECSuccess
}

}

pub fn ssl_connect(addr: SocketAddr, hostname: ~str) -> SSLStream
{
    unsafe {

    let oldmodel = PR_OpenTCPSocket(PR_AF_INET);
    let model = SSL_ImportFD(ptr::null(), oldmodel);
    do nss_cmd { SSL_OptionSet(model, SSL_ENABLE_SSL2, PRFalse) };
    do nss_cmd { SSL_OptionSet(model, SSL_V2_COMPATIBLE_HELLO, PRFalse) };
    do nss_cmd { SSL_OptionSet(model, SSL_ENABLE_DEFLATE, PRFalse) };
    let sslfd = PR_OpenTCPSocket(PR_AF_INET);
    PR_Connect(sslfd, &PRNetAddr { family: PR_AF_INET, ip: PR_htonl(IpAddrToBytes(addr.ip)), port: PR_htons(addr.port), pad: [0,0,0,0,0,0,0,0] }, 30000);
    let ssl_socket = SSL_ImportFD(model, sslfd);
    PR_Close(model);
    do nss_cmd { SSL_ResetHandshake(ssl_socket, PRFalse) };
    do nss_cmd { SSL_SetURL(ssl_socket, hostname.to_c_str().unwrap()) };
    do nss_cmd { SSL_ForceHandshake(ssl_socket) };

    SSLStream { sslfd: ssl_socket, is_eof: false }

    }
}

pub fn nss_cmd(blk: &fn() -> SECStatus) {
    let result = blk();
    if(result == SECFailure) {
      fail!("NSS Failed with {}", unsafe { std::str::raw::from_c_str(PR_ErrorToName(PR_GetError())) });
    }
}

pub struct SSLStream {
    sslfd: *c_void,
    is_eof: bool,
}

impl Reader for SSLStream {
    fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
    match unsafe { PR_Read(self.sslfd, vec::raw::to_ptr(buf) as *c_void, buf.len() as i32) } {
     0 => { self.is_eof = true; None },
     -1 => None,
     bytes_read => Some(bytes_read as uint)
    }
}
       fn eof(&mut self) -> bool {
            self.is_eof
       }
}

impl Writer for SSLStream {
    fn write(&mut self, buf: &[u8]) {
        unsafe { PR_Write(self.sslfd, vec::raw::to_ptr(buf) as *c_void, buf.len() as i32) };
    }
    fn flush(&mut self) {
        //nop
    }
}

pub fn IpAddrToBytes(addr: IpAddr) -> u32 {
match addr {
        Ipv4Addr(o1, o2, o3, o4) => ((o1 as u32 << 24) + (o2 as u32 << 16) + (o3 as u32 << 8) + (o4 as u32 << 0)) as u32,
        _ => 0u32 }
}

<|endoftext|>


<commit_before>use byteorder::{ReadBytesExt, LittleEndian};
use rwinstructs::timestamp::{WinTimestamp};
use rshellitems::shellitem::{ShellItem};
use lnkpkg::locationinfo::{LocationInfo};
use lnkpkg::flags::{DataFlags,FileFlags};
use lnkpkg::flags;
use lnkpkg::errors::{LnkError};
use lnkpkg::utils;
use std::io::SeekFrom;
use std::io::Read;
use std::io::Seek;

#[derive(Clone, Debug)]
pub struct Guid(pub [u8;16]);

#[derive(Debug)]
// 76 bytes long
pub struct ShellLinkHeader {
    pub header_size: u32,
    pub guid: Guid,
    pub data_flags: DataFlags,
    pub file_flags: FileFlags,
    pub created: WinTimestamp,
    pub accessed: WinTimestamp,
    pub modified: WinTimestamp,
    pub file_size: u32,
    pub icon_offset: i32,
    pub window_flag: u32,
    pub hot_key: u16,
    pub unknown1: u16,
    pub unknown2: u32,
    pub unknown3: u32
}

impl ShellLinkHeader {
    pub fn new<R: Read>(mut reader: R) -> Result<ShellLinkHeader,LnkError> {
        let header_size = reader.read_u32::<LittleEndian>()?;
        let mut guid = Guid([0; 16]);
        reader.read_exact(&mut guid.0)?;

        let data_flags = DataFlags::from_bits_truncate(
            reader.read_u32::<LittleEndian>()?
        );

        let file_flags = FileFlags::from_bits_truncate(
            reader.read_u32::<LittleEndian>()?
        );
        let created = WinTimestamp(reader.read_u64::<LittleEndian>()?);
        let accessed = WinTimestamp(reader.read_u64::<LittleEndian>()?);
        let modified = WinTimestamp(reader.read_u64::<LittleEndian>()?);
        let file_size = reader.read_u32::<LittleEndian>()?;
        let icon_offset = reader.read_i32::<LittleEndian>()?;
        let window_flag = reader.read_u32::<LittleEndian>()?;
        let hot_key = reader.read_u16::<LittleEndian>()?;
        let unknown1 = reader.read_u16::<LittleEndian>()?;
        let unknown2 = reader.read_u32::<LittleEndian>()?;
        let unknown3 = reader.read_u32::<LittleEndian>()?;

        Ok(
            ShellLinkHeader {
                header_size: header_size,
                guid: guid,
                data_flags: data_flags,
                file_flags: file_flags,
                created: created,
                accessed: accessed,
                modified: modified,
                file_size: file_size,
                icon_offset: icon_offset,
                window_flag: window_flag,
                hot_key: hot_key,
                unknown1: unknown1,
                unknown2: unknown2,
                unknown3: unknown3
            }
        )
    }

    pub fn get_data_flags(&self) -> DataFlags {
        self.data_flags
    }
}

#[derive(Debug)]
pub struct TargetIdList {
    pub list_size: u16,
    pub shell_items: Vec<ShellItem>
}

impl TargetIdList{
    pub fn new<R: Read>(mut reader: R) -> Result<TargetIdList, LnkError> {
        let list_size = reader.read_u16::<LittleEndian>()?;
        let mut shell_items: Vec<ShellItem> = Vec::new();

        let mut total_read: u16 = 0;
        while total_read < list_size {
            let mut shell_item = ShellItem::new(&mut reader)?;
            let size = shell_item.get_size();
            total_read += size;

            if size == 0 {
                // Null shell item is terminator
                break
            }

            shell_items.push(shell_item);
        }

        Ok(
            TargetIdList {
                list_size: list_size,
                shell_items: shell_items
            }
        )
    }

    pub fn get_size(&self) -> u16 {
        self.list_size
    }
}

#[derive(Debug)]
pub struct DataStrings {
    pub description: Option<String>,
    pub relative_path: Option<String>,
    pub working_directory: Option<String>,
    pub command_line_args: Option<String>,
    pub icon_location: Option<String>
}
impl DataStrings {
    pub fn new<R: Read>(mut reader: R, data_flags: DataFlags) -> Result<DataStrings,LnkError> {
        let unicode_flag = data_flags.contains(flags::IS_UNICODE);

        let mut description = None;
        if data_flags.contains(flags::HAS_NAME) {
            if unicode_flag {
                description = Some(utils::read_string_u16_w_size(&mut reader)?);
            } else {
                description = Some(utils::read_string_u8_w_size(&mut reader)?);
            }
        }

        let mut relative_path = None;
        if data_flags.contains(flags::HAS_RELATIVE_PATH) {
            if unicode_flag {
                relative_path = Some(utils::read_string_u16_w_size(&mut reader)?);
            } else {
                relative_path = Some(utils::read_string_u8_w_size(&mut reader)?);
            }
        }

        let mut working_directory = None;
        if data_flags.contains(flags::HAS_WORKING_DIR) {
            if unicode_flag {
                working_directory = Some(utils::read_string_u16_w_size(&mut reader)?);
            } else {
                working_directory = Some(utils::read_string_u8_w_size(&mut reader)?);
            }
        }

        let mut command_line_args = None;
        if data_flags.contains(flags::HAS_ARGUMENTS) {
            if unicode_flag {
                command_line_args = Some(utils::read_string_u16_w_size(&mut reader)?);
            } else {
                command_line_args = Some(utils::read_string_u8_w_size(&mut reader)?);
            }
        }

        let mut icon_location = None;
        if data_flags.contains(flags::HAS_ICON_LOCATION) {
            if unicode_flag {
                icon_location = Some(utils::read_string_u16_w_size(&mut reader)?);
            } else {
                icon_location = Some(utils::read_string_u8_w_size(&mut reader)?);
            }
        }

        Ok(
            DataStrings {
                description: description,
                relative_path: relative_path,
                working_directory: working_directory,
                command_line_args: command_line_args,
                icon_location: icon_location
            }
        )
    }
}

#[derive(Debug)]
pub struct Lnk {
    pub header: ShellLinkHeader,
    pub target_list: Option<TargetIdList>,
    pub location_info: Option<LocationInfo>,
    pub data_strings: DataStrings
}

impl Lnk {
    pub fn new<Rs: Read+Seek>(mut reader: Rs) -> Result<Lnk,LnkError> {
        let header = ShellLinkHeader::new(&mut reader)?;
        let header_flags = header.get_data_flags();

        let mut target_list = None;
        if header_flags.contains(flags::HAS_TARGET_ID_LIST) {
            target_list = Some(TargetIdList::new(&mut reader)?);
        }

        let mut location_offset = reader.seek(
            SeekFrom::Current(0)
        )?;

        let mut location_info = None;
        if header_flags.contains(flags::HAS_LINK_INFO) {
            location_info = Some(LocationInfo::new(&mut reader)?);
        }

        println!("offset: {}",reader.seek(
            SeekFrom::Current(0)
        )?);
        let data_strings = DataStrings::new(
            &mut reader,
            header_flags
        )?;

        Ok(
            Lnk {
                header: header,
                target_list: target_list,
                location_info: location_info,
                data_strings: data_strings
            }
        )
    }
}
<commit_msg>added debug print statements if needed<commit_after>use byteorder::{ReadBytesExt, LittleEndian};
use rwinstructs::timestamp::{WinTimestamp};
use rshellitems::shellitem::{ShellItem};
use lnkpkg::locationinfo::{LocationInfo};
use lnkpkg::flags::{DataFlags,FileFlags};
use lnkpkg::flags;
use lnkpkg::errors::{LnkError};
use lnkpkg::utils;
use std::io::SeekFrom;
use std::io::Read;
use std::io::Seek;

#[derive(Clone, Debug)]
pub struct Guid(pub [u8;16]);

#[derive(Debug)]
// 76 bytes long
pub struct ShellLinkHeader {
    pub header_size: u32,
    pub guid: Guid,
    pub data_flags: DataFlags,
    pub file_flags: FileFlags,
    pub created: WinTimestamp,
    pub accessed: WinTimestamp,
    pub modified: WinTimestamp,
    pub file_size: u32,
    pub icon_offset: i32,
    pub window_flag: u32,
    pub hot_key: u16,
    pub unknown1: u16,
    pub unknown2: u32,
    pub unknown3: u32
}

impl ShellLinkHeader {
    pub fn new<R: Read>(mut reader: R) -> Result<ShellLinkHeader,LnkError> {
        let header_size = reader.read_u32::<LittleEndian>()?;
        let mut guid = Guid([0; 16]);
        reader.read_exact(&mut guid.0)?;

        let data_flags = DataFlags::from_bits_truncate(
            reader.read_u32::<LittleEndian>()?
        );

        let file_flags = FileFlags::from_bits_truncate(
            reader.read_u32::<LittleEndian>()?
        );
        let created = WinTimestamp(reader.read_u64::<LittleEndian>()?);
        let accessed = WinTimestamp(reader.read_u64::<LittleEndian>()?);
        let modified = WinTimestamp(reader.read_u64::<LittleEndian>()?);
        let file_size = reader.read_u32::<LittleEndian>()?;
        let icon_offset = reader.read_i32::<LittleEndian>()?;
        let window_flag = reader.read_u32::<LittleEndian>()?;
        let hot_key = reader.read_u16::<LittleEndian>()?;
        let unknown1 = reader.read_u16::<LittleEndian>()?;
        let unknown2 = reader.read_u32::<LittleEndian>()?;
        let unknown3 = reader.read_u32::<LittleEndian>()?;

        Ok(
            ShellLinkHeader {
                header_size: header_size,
                guid: guid,
                data_flags: data_flags,
                file_flags: file_flags,
                created: created,
                accessed: accessed,
                modified: modified,
                file_size: file_size,
                icon_offset: icon_offset,
                window_flag: window_flag,
                hot_key: hot_key,
                unknown1: unknown1,
                unknown2: unknown2,
                unknown3: unknown3
            }
        )
    }

    pub fn get_data_flags(&self) -> DataFlags {
        self.data_flags
    }
}

#[derive(Debug)]
pub struct TargetIdList {
    pub list_size: u16,
    pub shell_items: Vec<ShellItem>
}

impl TargetIdList{
    pub fn new<R: Read>(mut reader: R) -> Result<TargetIdList, LnkError> {
        let list_size = reader.read_u16::<LittleEndian>()?;
        let mut shell_items: Vec<ShellItem> = Vec::new();

        let mut total_read: u16 = 0;
        while total_read < list_size {
            let mut shell_item = ShellItem::new(&mut reader)?;
            let size = shell_item.get_size();
            total_read += size;

            if size == 0 {
                // Null shell item is terminator
                break
            }

            shell_items.push(shell_item);
        }

        Ok(
            TargetIdList {
                list_size: list_size,
                shell_items: shell_items
            }
        )
    }

    pub fn get_size(&self) -> u16 {
        self.list_size
    }
}

#[derive(Debug)]
pub struct DataStrings {
    pub description: Option<String>,
    pub relative_path: Option<String>,
    pub working_directory: Option<String>,
    pub command_line_args: Option<String>,
    pub icon_location: Option<String>
}
impl DataStrings {
    pub fn new<R: Read>(mut reader: R, data_flags: DataFlags) -> Result<DataStrings,LnkError> {
        let unicode_flag = data_flags.contains(flags::IS_UNICODE);

        let mut description = None;
        if data_flags.contains(flags::HAS_NAME) {
            if unicode_flag {
                description = Some(utils::read_string_u16_w_size(&mut reader)?);
            } else {
                description = Some(utils::read_string_u8_w_size(&mut reader)?);
            }
        }

        let mut relative_path = None;
        if data_flags.contains(flags::HAS_RELATIVE_PATH) {
            if unicode_flag {
                relative_path = Some(utils::read_string_u16_w_size(&mut reader)?);
            } else {
                relative_path = Some(utils::read_string_u8_w_size(&mut reader)?);
            }
        }

        let mut working_directory = None;
        if data_flags.contains(flags::HAS_WORKING_DIR) {
            if unicode_flag {
                working_directory = Some(utils::read_string_u16_w_size(&mut reader)?);
            } else {
                working_directory = Some(utils::read_string_u8_w_size(&mut reader)?);
            }
        }

        let mut command_line_args = None;
        if data_flags.contains(flags::HAS_ARGUMENTS) {
            if unicode_flag {
                command_line_args = Some(utils::read_string_u16_w_size(&mut reader)?);
            } else {
                command_line_args = Some(utils::read_string_u8_w_size(&mut reader)?);
            }
        }

        let mut icon_location = None;
        if data_flags.contains(flags::HAS_ICON_LOCATION) {
            if unicode_flag {
                icon_location = Some(utils::read_string_u16_w_size(&mut reader)?);
            } else {
                icon_location = Some(utils::read_string_u8_w_size(&mut reader)?);
            }
        }

        Ok(
            DataStrings {
                description: description,
                relative_path: relative_path,
                working_directory: working_directory,
                command_line_args: command_line_args,
                icon_location: icon_location
            }
        )
    }
}

#[derive(Debug)]
pub struct Lnk {
    pub header: ShellLinkHeader,
    pub target_list: Option<TargetIdList>,
    pub location_info: Option<LocationInfo>,
    pub data_strings: DataStrings
}

impl Lnk {
    pub fn new<Rs: Read+Seek>(mut reader: Rs) -> Result<Lnk,LnkError> {
        let header = ShellLinkHeader::new(&mut reader)?;
        let header_flags = header.get_data_flags();

        let mut target_list = None;
        if header_flags.contains(flags::HAS_TARGET_ID_LIST) {
            // println!("target_list starting offset: {}",reader.seek(SeekFrom::Current(0))?);
            target_list = Some(TargetIdList::new(&mut reader)?);
        }

        let mut location_info = None;
        if header_flags.contains(flags::HAS_LINK_INFO) {
            // println!("location_info starting offset: {}",reader.seek(SeekFrom::Current(0))?);
            location_info = Some(LocationInfo::new(&mut reader)?);
        }

        // println!("data_strings starting offset: {}",reader.seek(SeekFrom::Current(0))?);
        let data_strings = DataStrings::new(
            &mut reader,
            header_flags
        )?;

        Ok(
            Lnk {
                header: header,
                target_list: target_list,
                location_info: location_info,
                data_strings: data_strings
            }
        )
    }
}
<|endoftext|>


<commit_before>extern crate bls;
extern crate boolean_bitfield;
extern crate ethereum_types;
extern crate ssz;

pub mod test_utils;

pub mod attestation;
pub mod attestation_data;
pub mod attestation_data_and_custody_bit;
pub mod beacon_block;
pub mod beacon_block_body;
pub mod beacon_state;
pub mod candidate_pow_receipt_root_record;
pub mod casper_slashing;
pub mod crosslink_record;
pub mod deposit;
pub mod deposit_data;
pub mod deposit_input;
pub mod exit;
pub mod fork_data;
pub mod pending_attestation_record;
pub mod proposal_signed_data;
pub mod proposer_slashing;
pub mod shard_committee;
pub mod shard_reassignment_record;
pub mod slashable_vote_data;
pub mod special_record;
pub mod validator_record;
pub mod validator_registry;

pub mod readers;

use self::ethereum_types::{H160, H256, U256};
use std::collections::HashMap;

pub use crate::attestation::Attestation;
pub use crate::attestation_data::AttestationData;
pub use crate::attestation_data_and_custody_bit::AttestationDataAndCustodyBit;
pub use crate::beacon_block::BeaconBlock;
pub use crate::beacon_block_body::BeaconBlockBody;
pub use crate::beacon_state::BeaconState;
pub use crate::casper_slashing::CasperSlashing;
pub use crate::crosslink_record::CrosslinkRecord;
pub use crate::deposit::Deposit;
pub use crate::deposit_data::DepositData;
pub use crate::deposit_input::DepositInput;
pub use crate::exit::Exit;
pub use crate::fork_data::ForkData;
pub use crate::pending_attestation_record::PendingAttestationRecord;
pub use crate::proposal_signed_data::ProposalSignedData;
pub use crate::proposer_slashing::ProposerSlashing;
pub use crate::shard_committee::ShardCommittee;
pub use crate::slashable_vote_data::SlashableVoteData;
pub use crate::special_record::{SpecialRecord, SpecialRecordKind};
pub use crate::validator_record::{StatusFlags as ValidatorStatusFlags, ValidatorRecord};

pub type Hash256 = H256;
pub type Address = H160;
pub type EthBalance = U256;
pub type Bitfield = boolean_bitfield::BooleanBitfield;
pub type BitfieldError = boolean_bitfield::Error;

/// Maps a (slot, shard_id) to attestation_indices.
pub type AttesterMap = HashMap<(u64, u64), Vec<usize>>;

/// Maps a slot to a block proposer.
pub type ProposerMap = HashMap<u64, usize>;

pub use bls::{AggregatePublicKey, AggregateSignature, PublicKey, Signature};
<commit_msg>Export bls::Keypair from types crate<commit_after>extern crate bls;
extern crate boolean_bitfield;
extern crate ethereum_types;
extern crate ssz;

pub mod test_utils;

pub mod attestation;
pub mod attestation_data;
pub mod attestation_data_and_custody_bit;
pub mod beacon_block;
pub mod beacon_block_body;
pub mod beacon_state;
pub mod candidate_pow_receipt_root_record;
pub mod casper_slashing;
pub mod crosslink_record;
pub mod deposit;
pub mod deposit_data;
pub mod deposit_input;
pub mod exit;
pub mod fork_data;
pub mod pending_attestation_record;
pub mod proposal_signed_data;
pub mod proposer_slashing;
pub mod shard_committee;
pub mod shard_reassignment_record;
pub mod slashable_vote_data;
pub mod special_record;
pub mod validator_record;
pub mod validator_registry;

pub mod readers;

use self::ethereum_types::{H160, H256, U256};
use std::collections::HashMap;

pub use crate::attestation::Attestation;
pub use crate::attestation_data::AttestationData;
pub use crate::attestation_data_and_custody_bit::AttestationDataAndCustodyBit;
pub use crate::beacon_block::BeaconBlock;
pub use crate::beacon_block_body::BeaconBlockBody;
pub use crate::beacon_state::BeaconState;
pub use crate::casper_slashing::CasperSlashing;
pub use crate::crosslink_record::CrosslinkRecord;
pub use crate::deposit::Deposit;
pub use crate::deposit_data::DepositData;
pub use crate::deposit_input::DepositInput;
pub use crate::exit::Exit;
pub use crate::fork_data::ForkData;
pub use crate::pending_attestation_record::PendingAttestationRecord;
pub use crate::proposal_signed_data::ProposalSignedData;
pub use crate::proposer_slashing::ProposerSlashing;
pub use crate::shard_committee::ShardCommittee;
pub use crate::slashable_vote_data::SlashableVoteData;
pub use crate::special_record::{SpecialRecord, SpecialRecordKind};
pub use crate::validator_record::{StatusFlags as ValidatorStatusFlags, ValidatorRecord};

pub type Hash256 = H256;
pub type Address = H160;
pub type EthBalance = U256;
pub type Bitfield = boolean_bitfield::BooleanBitfield;
pub type BitfieldError = boolean_bitfield::Error;

/// Maps a (slot, shard_id) to attestation_indices.
pub type AttesterMap = HashMap<(u64, u64), Vec<usize>>;

/// Maps a slot to a block proposer.
pub type ProposerMap = HashMap<u64, usize>;

pub use bls::{AggregatePublicKey, AggregateSignature, Keypair, PublicKey, Signature};
<|endoftext|>


<commit_before>/// Based on the bunnymark example from [`tetra`](https://crates.io/crates/tetra)
/// which is based on https://github.com/openfl/openfl-samples/tree/master/demos/BunnyMark
/// Original BunnyMark (and sprite) by Iain Lobb
use std::env;
use std::path;

use oorandom::Rand32;

use ggez::graphics::{spritebatch::SpriteBatch, Color, Image};
use ggez::Context;
use ggez::*;

use glam::*;

// NOTE: Using a high number here yields worse performance than adding more bunnies over
// time - I think this is due to all of the RNG being run on the same tick...
const INITIAL_BUNNIES: usize = 100;
const WIDTH: u16 = 1280;
const HEIGHT: u16 = 720;
const GRAVITY: f32 = 0.5;

struct Bunny {
    position: Vec2,
    velocity: Vec2,
}

impl Bunny {
    fn new(rng: &mut Rand32) -> Bunny {
        let x_vel = rng.rand_float() * 5.0;
        let y_vel = (rng.rand_float() * 5.0) - 2.5;

        Bunny {
            position: Vec2::new(0.0, 0.0),
            velocity: Vec2::new(x_vel, y_vel),
        }
    }
}

struct GameState {
    rng: Rand32,
    texture: Image,
    bunnies: Vec<Bunny>,
    max_x: f32,
    max_y: f32,

    click_timer: i32,
    bunnybatch: SpriteBatch,
    batched_drawing: bool,
}

impl GameState {
    fn new(ctx: &mut Context) -> ggez::GameResult<GameState> {
        // We just use the same RNG seed every time.
        let mut rng = Rand32::new(12345);
        let texture = Image::new(ctx, "/wabbit_alpha.png")?;
        let mut bunnies = Vec::with_capacity(INITIAL_BUNNIES);
        let max_x = (WIDTH - texture.width()) as f32;
        let max_y = (HEIGHT - texture.height()) as f32;

        for _ in 0..INITIAL_BUNNIES {
            bunnies.push(Bunny::new(&mut rng));
        }

        let bunnybatch = SpriteBatch::new(texture.clone());

        Ok(GameState {
            rng,
            texture,
            bunnies,
            max_x,
            max_y,

            click_timer: 0,
            bunnybatch,
            batched_drawing: true,
        })
    }
}

impl event::EventHandler for GameState {
    fn update(&mut self, _ctx: &mut Context) -> GameResult {
        if self.click_timer > 0 {
            self.click_timer -= 1;
        }

        for bunny in &mut self.bunnies {
            bunny.position += bunny.velocity;
            bunny.velocity += Vec2::new(0.0, GRAVITY);

            if bunny.position.x() > self.max_x {
                bunny.velocity *= Vec2::new(-1.0, 0.);
                bunny.position.set_x(self.max_x);
            } else if bunny.position.x() < 0.0 {
                bunny.velocity *= Vec2::new(-1.0, 0.0);
                bunny.position.set_x(0.0);
            }

            if bunny.position.y() > self.max_y {
                bunny.velocity.set_y(bunny.position.y() * -0.8);
                bunny.position.set_y(self.max_y);

                // Flip a coin
                if self.rng.rand_i32() > 0 {
                    bunny.velocity -= Vec2::new(0.0, 3.0 + (self.rng.rand_float() * 4.0));
                }
            } else if bunny.position.y() < 0.0 {
                bunny.velocity.set_y(0.0);
                bunny.position.set_y(0.0);
            }
        }

        Ok(())
    }

    fn draw(&mut self, ctx: &mut Context) -> GameResult {
        graphics::clear(ctx, Color::from((0.392, 0.584, 0.929)));

        if self.batched_drawing {
            self.bunnybatch.clear();
            for bunny in &self.bunnies {
                self.bunnybatch.add((bunny.position,));
            }
            graphics::draw(ctx, &self.bunnybatch, (Vec2::new(0.0, 0.0),))?;
        } else {
            for bunny in &self.bunnies {
                graphics::draw(ctx, &self.texture, (bunny.position,))?;
            }
        }

        graphics::set_window_title(
            ctx,
            &format!(
                "BunnyMark - {} bunnies - {:.0} FPS - batched drawing: {}",
                self.bunnies.len(),
                timer::fps(ctx),
                self.batched_drawing
            ),
        );
        graphics::present(ctx)?;

        Ok(())
    }

    fn key_down_event(
        &mut self,
        _ctx: &mut Context,
        keycode: event::KeyCode,
        _keymods: event::KeyMods,
        _repeat: bool,
    ) {
        if keycode == event::KeyCode::Space {
            self.batched_drawing = !self.batched_drawing;
        }
    }

    fn mouse_button_down_event(
        &mut self,
        _ctx: &mut Context,
        button: input::mouse::MouseButton,
        _x: f32,
        _y: f32,
    ) {
        if button == input::mouse::MouseButton::Left && self.click_timer == 0 {
            for _ in 0..INITIAL_BUNNIES {
                self.bunnies.push(Bunny::new(&mut self.rng));
            }
            self.click_timer = 10;
        }
    }
}

fn main() -> GameResult {
    let resource_dir = if let Ok(manifest_dir) = env::var("CARGO_MANIFEST_DIR") {
        let mut path = path::PathBuf::from(manifest_dir);
        path.push("resources");
        path
    } else {
        path::PathBuf::from("./resources")
    };

    let cb = ggez::ContextBuilder::new("bunnymark", "ggez").add_resource_path(resource_dir);
    let (ctx, event_loop) = &mut cb.build()?;

    let state = &mut GameState::new(ctx)?;
    event::run(ctx, event_loop, state)
}
<commit_msg>Update bunnymark a little<commit_after>/// Based on the bunnymark example from [`tetra`](https://crates.io/crates/tetra)
/// which is based on https://github.com/openfl/openfl-samples/tree/master/demos/BunnyMark
/// Original BunnyMark (and sprite) by Iain Lobb
use std::env;
use std::path;

use oorandom::Rand32;

use ggez::graphics::{spritebatch::SpriteBatch, Color, Image};
use ggez::Context;
use ggez::*;

use glam::*;

// NOTE: Using a high number here yields worse performance than adding more bunnies over
// time - I think this is due to all of the RNG being run on the same tick...
const INITIAL_BUNNIES: usize = 1000;
const WIDTH: u16 = 1280;
const HEIGHT: u16 = 720;
const GRAVITY: f32 = 0.5;

struct Bunny {
    position: Vec2,
    velocity: Vec2,
}

impl Bunny {
    fn new(rng: &mut Rand32) -> Bunny {
        let x_vel = rng.rand_float() * 5.0;
        let y_vel = (rng.rand_float() * 5.0) - 2.5;

        Bunny {
            position: Vec2::new(0.0, 0.0),
            velocity: Vec2::new(x_vel, y_vel),
        }
    }
}

struct GameState {
    rng: Rand32,
    texture: Image,
    bunnies: Vec<Bunny>,
    max_x: f32,
    max_y: f32,

    click_timer: i32,
    bunnybatch: SpriteBatch,
    batched_drawing: bool,
}

impl GameState {
    fn new(ctx: &mut Context) -> ggez::GameResult<GameState> {
        // We just use the same RNG seed every time.
        let mut rng = Rand32::new(12345);
        let texture = Image::new(ctx, "/wabbit_alpha.png")?;
        let mut bunnies = Vec::with_capacity(INITIAL_BUNNIES);
        let max_x = (WIDTH - texture.width()) as f32;
        let max_y = (HEIGHT - texture.height()) as f32;

        for _ in 0..INITIAL_BUNNIES {
            bunnies.push(Bunny::new(&mut rng));
        }

        let bunnybatch = SpriteBatch::new(texture.clone());

        Ok(GameState {
            rng,
            texture,
            bunnies,
            max_x,
            max_y,

            click_timer: 0,
            bunnybatch,
            batched_drawing: true,
        })
    }
}

impl event::EventHandler for GameState {
    fn update(&mut self, _ctx: &mut Context) -> GameResult {
        if self.click_timer > 0 {
            self.click_timer -= 1;
        }

        for bunny in &mut self.bunnies {
            bunny.position += bunny.velocity;
            bunny.velocity += Vec2::new(0.0, GRAVITY);

            if bunny.position.x() > self.max_x {
                bunny.velocity *= Vec2::new(-1.0, 0.);
                bunny.position.set_x(self.max_x);
            } else if bunny.position.x() < 0.0 {
                bunny.velocity *= Vec2::new(-1.0, 0.0);
                bunny.position.set_x(0.0);
            }

            if bunny.position.y() > self.max_y {
                bunny.velocity.set_y(bunny.position.y() * -0.8);
                bunny.position.set_y(self.max_y);

                // Flip a coin
                if self.rng.rand_i32() > 0 {
                    bunny.velocity -= Vec2::new(0.0, 3.0 + (self.rng.rand_float() * 4.0));
                }
            } else if bunny.position.y() < 0.0 {
                bunny.velocity.set_y(0.0);
                bunny.position.set_y(0.0);
            }
        }

        Ok(())
    }

    fn draw(&mut self, ctx: &mut Context) -> GameResult {
        graphics::clear(ctx, Color::from((0.392, 0.584, 0.929)));

        if self.batched_drawing {
            self.bunnybatch.clear();
            for bunny in &self.bunnies {
                self.bunnybatch.add((bunny.position,));
            }
            graphics::draw(ctx, &self.bunnybatch, (Vec2::new(0.0, 0.0),))?;
        } else {
            for bunny in &self.bunnies {
                graphics::draw(ctx, &self.texture, (bunny.position,))?;
            }
        }

        graphics::set_window_title(
            ctx,
            &format!(
                "BunnyMark - {} bunnies - {:.0} FPS - batched drawing: {}",
                self.bunnies.len(),
                timer::fps(ctx),
                self.batched_drawing
            ),
        );
        graphics::present(ctx)?;

        Ok(())
    }

    fn key_down_event(
        &mut self,
        _ctx: &mut Context,
        keycode: event::KeyCode,
        _keymods: event::KeyMods,
        _repeat: bool,
    ) {
        if keycode == event::KeyCode::Space {
            self.batched_drawing = !self.batched_drawing;
        }
    }

    fn mouse_button_down_event(
        &mut self,
        _ctx: &mut Context,
        button: input::mouse::MouseButton,
        _x: f32,
        _y: f32,
    ) {
        if button == input::mouse::MouseButton::Left && self.click_timer == 0 {
            for _ in 0..INITIAL_BUNNIES {
                self.bunnies.push(Bunny::new(&mut self.rng));
            }
            self.click_timer = 10;
        }
    }
}

fn main() -> GameResult {
    let resource_dir = if let Ok(manifest_dir) = env::var("CARGO_MANIFEST_DIR") {
        let mut path = path::PathBuf::from(manifest_dir);
        path.push("resources");
        path
    } else {
        path::PathBuf::from("./resources")
    };

    let cb = ggez::ContextBuilder::new("bunnymark", "ggez").add_resource_path(resource_dir);
    let (mut ctx, event_loop) = cb.build()?;

    let state = GameState::new(&mut ctx)?;
    event::run(ctx, event_loop, state)
}
<|endoftext|>


<commit_before>use ide_db::base_db::{FileId, SourceDatabase};
use ide_db::RootDatabase;
use syntax::{
    AstNode, NodeOrToken, SourceFile, SyntaxKind::STRING, SyntaxToken, TextRange, TextSize,
};

// Feature: Show Syntax Tree
//
// Shows the parse tree of the current file. It exists mostly for debugging
// rust-analyzer itself.
//
// |===
// | Editor  | Action Name
//
// | VS Code | **Rust Analyzer: Show Syntax Tree**
// |===
pub(crate) fn syntax_tree(
    db: &RootDatabase,
    file_id: FileId,
    text_range: Option<TextRange>,
) -> String {
    let parse = db.parse(file_id);
    if let Some(text_range) = text_range {
        let node = match parse.tree().syntax().covering_element(text_range) {
            NodeOrToken::Node(node) => node,
            NodeOrToken::Token(token) => {
                if let Some(tree) = syntax_tree_for_string(&token, text_range) {
                    return tree;
                }
                token.parent()
            }
        };

        format!("{:#?}", node)
    } else {
        format!("{:#?}", parse.tree().syntax())
    }
}

/// Attempts parsing the selected contents of a string literal
/// as rust syntax and returns its syntax tree
fn syntax_tree_for_string(token: &SyntaxToken, text_range: TextRange) -> Option<String> {
    // When the range is inside a string
    // we'll attempt parsing it as rust syntax
    // to provide the syntax tree of the contents of the string
    match token.kind() {
        STRING => syntax_tree_for_token(token, text_range),
        _ => None,
    }
}

fn syntax_tree_for_token(node: &SyntaxToken, text_range: TextRange) -> Option<String> {
    // Range of the full node
    let node_range = node.text_range();
    let text = node.text().to_string();

    // We start at some point inside the node
    // Either we have selected the whole string
    // or our selection is inside it
    let start = text_range.start() - node_range.start();

    // how many characters we have selected
    let len = text_range.len();

    let node_len = node_range.len();

    let start = start;

    // We want to cap our length
    let len = len.min(node_len);

    // Ensure our slice is inside the actual string
    let end =
        if start + len < TextSize::of(&text) { start + len } else { TextSize::of(&text) - start };

    let text = &text[TextRange::new(start, end)];

    // Remove possible extra string quotes from the start
    // and the end of the string
    let text = text
        .trim_start_matches('r')
        .trim_start_matches('#')
        .trim_start_matches('"')
        .trim_end_matches('#')
        .trim_end_matches('"')
        .trim()
        // Remove custom markers
        .replace("$0", "");

    let parsed = SourceFile::parse(&text);

    // If the "file" parsed without errors,
    // return its syntax
    if parsed.errors().is_empty() {
        return Some(format!("{:#?}", parsed.tree().syntax()));
    }

    None
}

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

    use crate::fixture;

    #[test]
    fn test_syntax_tree_without_range() {
        // Basic syntax
        let (analysis, file_id) = fixture::file(r#"fn foo() {}"#);
        let syn = analysis.syntax_tree(file_id, None).unwrap();

        assert_eq_text!(
            r#"
SOURCE_FILE@0..11
  FN@0..11
    FN_KW@0..2 "fn"
    WHITESPACE@2..3 " "
    NAME@3..6
      IDENT@3..6 "foo"
    PARAM_LIST@6..8
      L_PAREN@6..7 "("
      R_PAREN@7..8 ")"
    WHITESPACE@8..9 " "
    BLOCK_EXPR@9..11
      L_CURLY@9..10 "{"
      R_CURLY@10..11 "}"
"#
            .trim(),
            syn.trim()
        );

        let (analysis, file_id) = fixture::file(
            r#"
fn test() {
    assert!("
    fn foo() {
    }
    ", "");
}"#
            .trim(),
        );
        let syn = analysis.syntax_tree(file_id, None).unwrap();

        assert_eq_text!(
            r#"
SOURCE_FILE@0..60
  FN@0..60
    FN_KW@0..2 "fn"
    WHITESPACE@2..3 " "
    NAME@3..7
      IDENT@3..7 "test"
    PARAM_LIST@7..9
      L_PAREN@7..8 "("
      R_PAREN@8..9 ")"
    WHITESPACE@9..10 " "
    BLOCK_EXPR@10..60
      L_CURLY@10..11 "{"
      WHITESPACE@11..16 "\n    "
      EXPR_STMT@16..58
        MACRO_CALL@16..57
          PATH@16..22
            PATH_SEGMENT@16..22
              NAME_REF@16..22
                IDENT@16..22 "assert"
          BANG@22..23 "!"
          TOKEN_TREE@23..57
            L_PAREN@23..24 "("
            STRING@24..52 "\"\n    fn foo() {\n     ..."
            COMMA@52..53 ","
            WHITESPACE@53..54 " "
            STRING@54..56 "\"\""
            R_PAREN@56..57 ")"
        SEMICOLON@57..58 ";"
      WHITESPACE@58..59 "\n"
      R_CURLY@59..60 "}"
"#
            .trim(),
            syn.trim()
        );
    }

    #[test]
    fn test_syntax_tree_with_range() {
        let (analysis, range) = fixture::range(r#"$0fn foo() {}$0"#.trim());
        let syn = analysis.syntax_tree(range.file_id, Some(range.range)).unwrap();

        assert_eq_text!(
            r#"
FN@0..11
  FN_KW@0..2 "fn"
  WHITESPACE@2..3 " "
  NAME@3..6
    IDENT@3..6 "foo"
  PARAM_LIST@6..8
    L_PAREN@6..7 "("
    R_PAREN@7..8 ")"
  WHITESPACE@8..9 " "
  BLOCK_EXPR@9..11
    L_CURLY@9..10 "{"
    R_CURLY@10..11 "}"
"#
            .trim(),
            syn.trim()
        );

        let (analysis, range) = fixture::range(
            r#"fn test() {
    $0assert!("
    fn foo() {
    }
    ", "");$0
}"#
            .trim(),
        );
        let syn = analysis.syntax_tree(range.file_id, Some(range.range)).unwrap();

        assert_eq_text!(
            r#"
EXPR_STMT@16..58
  MACRO_CALL@16..57
    PATH@16..22
      PATH_SEGMENT@16..22
        NAME_REF@16..22
          IDENT@16..22 "assert"
    BANG@22..23 "!"
    TOKEN_TREE@23..57
      L_PAREN@23..24 "("
      STRING@24..52 "\"\n    fn foo() {\n     ..."
      COMMA@52..53 ","
      WHITESPACE@53..54 " "
      STRING@54..56 "\"\""
      R_PAREN@56..57 ")"
  SEMICOLON@57..58 ";"
"#
            .trim(),
            syn.trim()
        );
    }

    #[test]
    fn test_syntax_tree_inside_string() {
        let (analysis, range) = fixture::range(
            r#"fn test() {
    assert!("
$0fn foo() {
}$0
fn bar() {
}
    ", "");
}"#
            .trim(),
        );
        let syn = analysis.syntax_tree(range.file_id, Some(range.range)).unwrap();
        assert_eq_text!(
            r#"
SOURCE_FILE@0..12
  FN@0..12
    FN_KW@0..2 "fn"
    WHITESPACE@2..3 " "
    NAME@3..6
      IDENT@3..6 "foo"
    PARAM_LIST@6..8
      L_PAREN@6..7 "("
      R_PAREN@7..8 ")"
    WHITESPACE@8..9 " "
    BLOCK_EXPR@9..12
      L_CURLY@9..10 "{"
      WHITESPACE@10..11 "\n"
      R_CURLY@11..12 "}"
"#
            .trim(),
            syn.trim()
        );

        // With a raw string
        let (analysis, range) = fixture::range(
            r###"fn test() {
    assert!(r#"
$0fn foo() {
}$0
fn bar() {
}
    "#, "");
}"###
                .trim(),
        );
        let syn = analysis.syntax_tree(range.file_id, Some(range.range)).unwrap();
        assert_eq_text!(
            r#"
SOURCE_FILE@0..12
  FN@0..12
    FN_KW@0..2 "fn"
    WHITESPACE@2..3 " "
    NAME@3..6
      IDENT@3..6 "foo"
    PARAM_LIST@6..8
      L_PAREN@6..7 "("
      R_PAREN@7..8 ")"
    WHITESPACE@8..9 " "
    BLOCK_EXPR@9..12
      L_CURLY@9..10 "{"
      WHITESPACE@10..11 "\n"
      R_CURLY@11..12 "}"
"#
            .trim(),
            syn.trim()
        );

        // With a raw string
        let (analysis, range) = fixture::range(
            r###"fn test() {
    assert!(r$0#"
fn foo() {
}
fn bar() {
}"$0#, "");
}"###
                .trim(),
        );
        let syn = analysis.syntax_tree(range.file_id, Some(range.range)).unwrap();
        assert_eq_text!(
            r#"
SOURCE_FILE@0..25
  FN@0..12
    FN_KW@0..2 "fn"
    WHITESPACE@2..3 " "
    NAME@3..6
      IDENT@3..6 "foo"
    PARAM_LIST@6..8
      L_PAREN@6..7 "("
      R_PAREN@7..8 ")"
    WHITESPACE@8..9 " "
    BLOCK_EXPR@9..12
      L_CURLY@9..10 "{"
      WHITESPACE@10..11 "\n"
      R_CURLY@11..12 "}"
  WHITESPACE@12..13 "\n"
  FN@13..25
    FN_KW@13..15 "fn"
    WHITESPACE@15..16 " "
    NAME@16..19
      IDENT@16..19 "bar"
    PARAM_LIST@19..21
      L_PAREN@19..20 "("
      R_PAREN@20..21 ")"
    WHITESPACE@21..22 " "
    BLOCK_EXPR@22..25
      L_CURLY@22..23 "{"
      WHITESPACE@23..24 "\n"
      R_CURLY@24..25 "}"
"#
            .trim(),
            syn.trim()
        );
    }
}
<commit_msg>Modernize tests<commit_after>use ide_db::base_db::{FileId, SourceDatabase};
use ide_db::RootDatabase;
use syntax::{
    AstNode, NodeOrToken, SourceFile, SyntaxKind::STRING, SyntaxToken, TextRange, TextSize,
};

// Feature: Show Syntax Tree
//
// Shows the parse tree of the current file. It exists mostly for debugging
// rust-analyzer itself.
//
// |===
// | Editor  | Action Name
//
// | VS Code | **Rust Analyzer: Show Syntax Tree**
// |===
pub(crate) fn syntax_tree(
    db: &RootDatabase,
    file_id: FileId,
    text_range: Option<TextRange>,
) -> String {
    let parse = db.parse(file_id);
    if let Some(text_range) = text_range {
        let node = match parse.tree().syntax().covering_element(text_range) {
            NodeOrToken::Node(node) => node,
            NodeOrToken::Token(token) => {
                if let Some(tree) = syntax_tree_for_string(&token, text_range) {
                    return tree;
                }
                token.parent()
            }
        };

        format!("{:#?}", node)
    } else {
        format!("{:#?}", parse.tree().syntax())
    }
}

/// Attempts parsing the selected contents of a string literal
/// as rust syntax and returns its syntax tree
fn syntax_tree_for_string(token: &SyntaxToken, text_range: TextRange) -> Option<String> {
    // When the range is inside a string
    // we'll attempt parsing it as rust syntax
    // to provide the syntax tree of the contents of the string
    match token.kind() {
        STRING => syntax_tree_for_token(token, text_range),
        _ => None,
    }
}

fn syntax_tree_for_token(node: &SyntaxToken, text_range: TextRange) -> Option<String> {
    // Range of the full node
    let node_range = node.text_range();
    let text = node.text().to_string();

    // We start at some point inside the node
    // Either we have selected the whole string
    // or our selection is inside it
    let start = text_range.start() - node_range.start();

    // how many characters we have selected
    let len = text_range.len();

    let node_len = node_range.len();

    let start = start;

    // We want to cap our length
    let len = len.min(node_len);

    // Ensure our slice is inside the actual string
    let end =
        if start + len < TextSize::of(&text) { start + len } else { TextSize::of(&text) - start };

    let text = &text[TextRange::new(start, end)];

    // Remove possible extra string quotes from the start
    // and the end of the string
    let text = text
        .trim_start_matches('r')
        .trim_start_matches('#')
        .trim_start_matches('"')
        .trim_end_matches('#')
        .trim_end_matches('"')
        .trim()
        // Remove custom markers
        .replace("$0", "");

    let parsed = SourceFile::parse(&text);

    // If the "file" parsed without errors,
    // return its syntax
    if parsed.errors().is_empty() {
        return Some(format!("{:#?}", parsed.tree().syntax()));
    }

    None
}

#[cfg(test)]
mod tests {
    use expect_test::expect;

    use crate::fixture;

    fn check(ra_fixture: &str, expect: expect_test::Expect) {
        let (analysis, file_id) = fixture::file(ra_fixture);
        let syn = analysis.syntax_tree(file_id, None).unwrap();
        expect.assert_eq(&syn)
    }
    fn check_range(ra_fixture: &str, expect: expect_test::Expect) {
        let (analysis, frange) = fixture::range(ra_fixture);
        let syn = analysis.syntax_tree(frange.file_id, Some(frange.range)).unwrap();
        expect.assert_eq(&syn)
    }

    #[test]
    fn test_syntax_tree_without_range() {
        // Basic syntax
        check(
            r#"fn foo() {}"#,
            expect![[r#"
                SOURCE_FILE@0..11
                  FN@0..11
                    FN_KW@0..2 "fn"
                    WHITESPACE@2..3 " "
                    NAME@3..6
                      IDENT@3..6 "foo"
                    PARAM_LIST@6..8
                      L_PAREN@6..7 "("
                      R_PAREN@7..8 ")"
                    WHITESPACE@8..9 " "
                    BLOCK_EXPR@9..11
                      L_CURLY@9..10 "{"
                      R_CURLY@10..11 "}"
            "#]],
        );

        check(
            r#"
fn test() {
    assert!("
    fn foo() {
    }
    ", "");
}"#,
            expect![[r#"
                SOURCE_FILE@0..60
                  FN@0..60
                    FN_KW@0..2 "fn"
                    WHITESPACE@2..3 " "
                    NAME@3..7
                      IDENT@3..7 "test"
                    PARAM_LIST@7..9
                      L_PAREN@7..8 "("
                      R_PAREN@8..9 ")"
                    WHITESPACE@9..10 " "
                    BLOCK_EXPR@10..60
                      L_CURLY@10..11 "{"
                      WHITESPACE@11..16 "\n    "
                      EXPR_STMT@16..58
                        MACRO_CALL@16..57
                          PATH@16..22
                            PATH_SEGMENT@16..22
                              NAME_REF@16..22
                                IDENT@16..22 "assert"
                          BANG@22..23 "!"
                          TOKEN_TREE@23..57
                            L_PAREN@23..24 "("
                            STRING@24..52 "\"\n    fn foo() {\n     ..."
                            COMMA@52..53 ","
                            WHITESPACE@53..54 " "
                            STRING@54..56 "\"\""
                            R_PAREN@56..57 ")"
                        SEMICOLON@57..58 ";"
                      WHITESPACE@58..59 "\n"
                      R_CURLY@59..60 "}"
            "#]],
        )
    }

    #[test]
    fn test_syntax_tree_with_range() {
        check_range(
            r#"$0fn foo() {}$0"#,
            expect![[r#"
                FN@0..11
                  FN_KW@0..2 "fn"
                  WHITESPACE@2..3 " "
                  NAME@3..6
                    IDENT@3..6 "foo"
                  PARAM_LIST@6..8
                    L_PAREN@6..7 "("
                    R_PAREN@7..8 ")"
                  WHITESPACE@8..9 " "
                  BLOCK_EXPR@9..11
                    L_CURLY@9..10 "{"
                    R_CURLY@10..11 "}"
            "#]],
        );

        check_range(
            r#"
fn test() {
    $0assert!("
    fn foo() {
    }
    ", "");$0
}"#,
            expect![[r#"
                EXPR_STMT@16..58
                  MACRO_CALL@16..57
                    PATH@16..22
                      PATH_SEGMENT@16..22
                        NAME_REF@16..22
                          IDENT@16..22 "assert"
                    BANG@22..23 "!"
                    TOKEN_TREE@23..57
                      L_PAREN@23..24 "("
                      STRING@24..52 "\"\n    fn foo() {\n     ..."
                      COMMA@52..53 ","
                      WHITESPACE@53..54 " "
                      STRING@54..56 "\"\""
                      R_PAREN@56..57 ")"
                  SEMICOLON@57..58 ";"
            "#]],
        );
    }

    #[test]
    fn test_syntax_tree_inside_string() {
        check_range(
            r#"fn test() {
    assert!("
$0fn foo() {
}$0
fn bar() {
}
    ", "");
}"#,
            expect![[r#"
                SOURCE_FILE@0..12
                  FN@0..12
                    FN_KW@0..2 "fn"
                    WHITESPACE@2..3 " "
                    NAME@3..6
                      IDENT@3..6 "foo"
                    PARAM_LIST@6..8
                      L_PAREN@6..7 "("
                      R_PAREN@7..8 ")"
                    WHITESPACE@8..9 " "
                    BLOCK_EXPR@9..12
                      L_CURLY@9..10 "{"
                      WHITESPACE@10..11 "\n"
                      R_CURLY@11..12 "}"
            "#]],
        );

        // With a raw string
        check_range(
            r###"fn test() {
    assert!(r#"
$0fn foo() {
}$0
fn bar() {
}
    "#, "");
}"###,
            expect![[r#"
                SOURCE_FILE@0..12
                  FN@0..12
                    FN_KW@0..2 "fn"
                    WHITESPACE@2..3 " "
                    NAME@3..6
                      IDENT@3..6 "foo"
                    PARAM_LIST@6..8
                      L_PAREN@6..7 "("
                      R_PAREN@7..8 ")"
                    WHITESPACE@8..9 " "
                    BLOCK_EXPR@9..12
                      L_CURLY@9..10 "{"
                      WHITESPACE@10..11 "\n"
                      R_CURLY@11..12 "}"
            "#]],
        );

        // With a raw string
        check_range(
            r###"fn test() {
    assert!(r$0#"
fn foo() {
}
fn bar() {
}"$0#, "");
}"###,
            expect![[r#"
                SOURCE_FILE@0..25
                  FN@0..12
                    FN_KW@0..2 "fn"
                    WHITESPACE@2..3 " "
                    NAME@3..6
                      IDENT@3..6 "foo"
                    PARAM_LIST@6..8
                      L_PAREN@6..7 "("
                      R_PAREN@7..8 ")"
                    WHITESPACE@8..9 " "
                    BLOCK_EXPR@9..12
                      L_CURLY@9..10 "{"
                      WHITESPACE@10..11 "\n"
                      R_CURLY@11..12 "}"
                  WHITESPACE@12..13 "\n"
                  FN@13..25
                    FN_KW@13..15 "fn"
                    WHITESPACE@15..16 " "
                    NAME@16..19
                      IDENT@16..19 "bar"
                    PARAM_LIST@19..21
                      L_PAREN@19..20 "("
                      R_PAREN@20..21 ")"
                    WHITESPACE@21..22 " "
                    BLOCK_EXPR@22..25
                      L_CURLY@22..23 "{"
                      WHITESPACE@23..24 "\n"
                      R_CURLY@24..25 "}"
            "#]],
        );
    }
}
<|endoftext|>