<commit_before>
// Provides the ```pnacl_test! {}``` macro.
// Usage:
//
// try one:
// ```rust
// pnacl_test! {
//    fn test_name() {
//        extern crate ppapi;
//        use std::collections::HashMap;
//        #[no_mangle]
//        pub extern fn ppapi_instance_created(_instance: ppapi::Instance,
//                                             _args: HashMap<String, String>) {
//            // Test logic here.
//        }
//    }
// }
// ```
// try two:
// ```rust
// #[ppapi_test]
// fn test_name(instance: ppapi::Instance) {
// }
// ```

#![crate_name = "ppapi-tester"]
#![crate_type = "dylib"]
#![feature(plugin_registrar, quote)]

#![allow(unstable)]

extern crate rustc;
extern crate syntax;

use syntax::ext::base::{SyntaxExtension, ExtCtxt};
use syntax::ext::build::AstBuilder;
use syntax::ext::quote::rt::{ToSource, ToTokens};
use syntax::parse::token::{intern, intern_and_get_ident};
use syntax::{ast, codemap};
use syntax::codemap::Span;
use syntax::ptr::P;
use rustc::plugin::Registry;

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    let ppapi_test_expander = SyntaxExtension::Modifier(Box::new(expand_test));
    let ppapi_test = intern("ppapi_test");
    reg.register_syntax_extension(ppapi_test, ppapi_test_expander);
}

const HTML: &'static str = include_str!("index.html");
const MANIFEST: &'static str = include_str!("manifest.nmf");

fn expand_test(ecx: &mut ExtCtxt,
               sp: Span,
               _meta_item: &ast::MetaItem,
               item: P<ast::Item>) -> P<ast::Item> {
    // we replace the input function with a function that instead compiles the
    // pretty printed original to a pexe and invokes chrome to simulate being
    // embedding in a website.

    println!("============");
    println!("{:?}", item);

    #[derive(PartialEq)]
    enum HasTestSignature {
        Yes,
        No,
        NotEvenAFunction,
    }

    fn has_correct_signature(i: &ast::Item) -> HasTestSignature {
        match &i.node {
          &ast::ItemFn(ref decl, _, _, ref generics, _) => {
            let no_output = match decl.output {
                ast::DefaultReturn(..) => true,
                _ => false
            };
            if decl.inputs.len() == 2
                   && no_output
                   && !generics.is_parameterized() {
                HasTestSignature::Yes
            } else {
                HasTestSignature::No
            }
          }
          _ => HasTestSignature::NotEvenAFunction,
        }
    }

    // first check that the annotated item is, in fact, a function:
    match has_correct_signature(&*item) {
        HasTestSignature::Yes => { println!("sig is fine"); },
        HasTestSignature::No => {
            ecx.span_err(sp, "function must be typed: fn(instance: \
                         ppapi::Instance, args: HashMap<String, String>) -> ()");
            return item;
        },
        HasTestSignature::NotEvenAFunction => {
            ecx.span_err(sp, "must be a function: fn(instance: ppapi::Instance, \
                         args: HashMap<String, String>) -> ()");
            return item;
        },
    }

    let test_name = item.ident;
    let wrapper =
        quote_item!(
            ecx,
            #![no_main]
            extern crate ppapi;

            use std::collections::HashMap;

            struct ResultMessager(ppapi::Messaging);
            impl Drop for ResultMessager {
                fn drop(&mut self) {
                    use std::rt::unwind::panicking;
                    let &mut ResultMessager(msg) = self;

                    if panicking() {
                        msg.post_message("failure");
                    } else {
                        msg.post_message("success");
                    }
                }
            }

            $item

            #[no_mangle] pub extern fn ppapi_instance_created(instance: ppapi::Instance,
                                                              args: HashMap<String, String>) {
                use ppapi::MessageLoop;
                assert!(MessageLoop::post_to_self(move |: _| {
                    let result = ResultMessager(instance.messaging());
                    $test_name(instance.clone(), args.clone());
                }).is_ok());
                assert!(MessageLoop::current().unwrap().shutdown().is_ok());
            }
            #[no_mangle] pub extern fn ppapi_instance_destroyed() { }
            );
    let wrapper = wrapper.expect("the wrapper failed to quote");
    let wrapper_ident = intern_and_get_ident(wrapper.to_source().as_slice());
    let wrapper_str = ecx.expr_str(sp, wrapper_ident);

    let cwd = ::std::os::getcwd().unwrap();
    let deps_str = cwd.join_many(["target", "le32-unknown-nacl", "deps"].as_slice())
        .display().to_string();
    let deps_ident = intern_and_get_ident(deps_str.as_slice());
    let deps_dir = ecx.expr_str(codemap::DUMMY_SP, deps_ident);

    let timeout = None::<u64>;

    let host_test =
        quote_item!(
            ecx,
            #[test] fn $test_name() {
                use std::io::TempDir;
                use std::io::fs::File;
                use std::io::{Command, LineBufferedWriter};
                use std::io::process::{ProcessExit, ProcessOutput};
                use std::io::stdio::{stdout, stderr, StdWriter};

                // the source to the real test:
                const REAL_TEST: &'static str = $wrapper_str;

                let tmp = TempDir::new(stringify!($test_name))
                    .ok().expect("need temp directory for test artifacts");

                let url = format!("file://{}",
                                  tmp.path().join("index.html").display());
                let chrome_args = ["--allow-file-access-from-files".to_string(),
                                   "--bwsi".to_string(),
                                   "--no-sandbox".to_string(),
                                   "--silent-launch".to_string(),
                                   "--noerrdialogs".to_string(),
                                   "--no-first-run".to_string(),
                                   "--no-default-browser-check".to_string(),
                                   url];

                let stdout_path = tmp.path().join("stdout");
                let stdout_name = stdout_path
                    .display().to_string();
                let stderr_path = tmp.path().join("stderr");
                let stderr_name = stderr_path
                    .display().to_string();
                let chrome_env = [("NACL_EXE_STDOUT".to_string(), stdout_name),
                                  ("NACL_EXE_STDERR".to_string(), stderr_name)];

                let rustc_args = ["-".to_string(),
                                  "-o".to_string(),
                                  tmp.path().join("test-main.pexe").display().to_string(),
                                  "--crate-type".to_string(), "bin".to_string(),
                                  "--target".to_string(),
                                  "le32-unknown-nacl".to_string(),
                                  "-L".to_string(),
                                  ($deps_dir).to_string()];
                let mut rustc = Command::new("rustc");
                rustc.args(rustc_args);
                println!("∨∨∨∨∨∨∨∨∨∨∨    rustc    ∨∨∨∨∨∨∨∨∨∨∨");
                println!("spawning `{:?}`", rustc);
                let mut rustc = rustc.spawn().unwrap();
                rustc.stdin
                    .as_mut()
                    .unwrap()
                    .write_str(REAL_TEST)
                    .unwrap();

                {
                    let path = tmp.path()
                        .join("index.html");
                    let file = File::create(&path).unwrap();
                    file.write_str($HTML).unwrap();
                }
                {
                    let path = tmp.path()
                        .join("manifest.nmf");
                    let file = File::create(&path).unwrap();
                    file.write_str($MANIFEST).unwrap();
                }

                match rustc.wait_with_output() {
                    Ok(ProcessOutput {
                        status: exit_status,
                        output: out, error: err,
                    }) => {
                        stdout().write(out.as_slice());
                        stderr().write(err.as_slice());
                        assert!(exit_status.success());
                    }
                    err => { err.unwrap(); },
                }
                println!("∧∧∧∧∧∧∧∧∧∧∧    rustc    ∧∧∧∧∧∧∧∧∧∧∧");

                let mut chrome = Command::new("google-chrome");
                chrome.args(chrome_args);
                for (k, v) in chrome_env.iter() {
                    chrome.env(k, v);
                }
                println!("∨∨∨∨∨∨∨∨∨∨∨   chrome    ∨∨∨∨∨∨∨∨∨∨∨");
                println!("spawning `{:?}`:", chrome);

                let mut chrome = chrome.spawn().unwrap();
                chrome.set_timeout($timeout);

                fn split_and_print(where_: LineBufferedWriter<StdWriter>,
                                   kind: &'static str, out: &[u8]) {
                    for line in out.split(move |: v| v == '\n' ) {
                        where_.write_str(kind).unwrap();
                        where_.write(line).unwrap();
                        where_.write_u8('\n').unwrap();
                    }
                }

                fn dump_output(cmd: &mut Process) {
                    let output = cmd.stdout
                        .as_mut().unwrap()
                        .read_to_end().unwrap();
                    let error = cmd.stderr
                        .as_mut().unwrap()
                        .read_to_end().unwrap();
                    split_and_print(stdout(), "stdout: ", output.as_slice());
                    split_and_print(stderr(), "stderr: ", error.as_slice());
                }

                match chrome.wait() {
                    Ok(status) => {
                        dump_output(&mut chrome);
                        assert!(status.success());
                    },
                    Err(IoError { kind: IoErrorKind::TimedOut, .. }) => {
                        println!("timeout! sending sigterm...");
                        chrome.set_timeout(Some(6000));
                        chrome.signal_exit().unwrap();
                        let res = chrome.wait();
                        let res = match res {
                            Err(IoError { kind: IoErrorKind::TimedOut, .. }) => {
                                println!("1s later: chrome still hasn't quit; killing.");
                                chrome.signal_kill().unwrap();
                                chrome.wait()
                            },
                            res => res,
                        }
                        dump_output(&mut chrome);
                        assert_eq!(res, Ok(ProcessExit::ExitStatus(0))); // always false.
                        unreachable!()
                    },
                    res => {
                        dump_output(&mut chrome);
                        res.unwrap();
                        unreachable!()
                    }
                }
                println!("∧∧∧∧∧∧∧∧∧∧∧   chrome    ∧∧∧∧∧∧∧∧∧∧∧");

                println!("∨∨∨∨∨∨∨∨∨∨∨ test output ∨∨∨∨∨∨∨∨∨∨∨");
                fn read_log(p: &Path) -> Vec<u8> {
                    let f = File::open(p).unwrap();
                    f.read_to_end().unwrap()
                }
                let test_stdout = read_log(&stdout_path);
                let test_stderr = read_log(&stderr_path);
                split_and_print(stdout(), "test stdout: ", test_stdout.as_slice());
                split_and_print(stderr(), "test stderr: ", test_stderr.as_slice());
                println!("∧∧∧∧∧∧∧∧∧∧∧ test output ∧∧∧∧∧∧∧∧∧∧∧");
            });
    host_test.unwrap()
}
<commit_msg>Fix documentation in ppapi-tester.<commit_after>// Copyright (c) 2014 Richard Diamond & contributors.
//
// This file is part of the Rust PPApi project.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

//! Provides the ```pnacl_test! {}``` macro.
//! Usage:
//! ```rust
//! #[ppapi_test]
//! fn test_name(instance: ppapi::Instance, args: HashMap<String, String>) {
//!    // Put the test here.
//! }
//! ```
//!
//! In the future I plan allowing #[ppapi_test] on modules so callbacks can be
//! tested as well.
//!

#![crate_name = "ppapi-tester"]
#![crate_type = "dylib"]
#![feature(plugin_registrar, quote)]

#![allow(unstable)]

extern crate rustc;
extern crate syntax;

use syntax::ext::base::{SyntaxExtension, ExtCtxt};
use syntax::ext::build::AstBuilder;
use syntax::ext::quote::rt::{ToSource, ToTokens};
use syntax::parse::token::{intern, intern_and_get_ident};
use syntax::{ast, codemap};
use syntax::codemap::Span;
use syntax::ptr::P;
use rustc::plugin::Registry;

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    let ppapi_test_expander = SyntaxExtension::Modifier(Box::new(expand_test));
    let ppapi_test = intern("ppapi_test");
    reg.register_syntax_extension(ppapi_test, ppapi_test_expander);
}

const HTML: &'static str = include_str!("index.html");
const MANIFEST: &'static str = include_str!("manifest.nmf");

fn expand_test(ecx: &mut ExtCtxt,
               sp: Span,
               _meta_item: &ast::MetaItem,
               item: P<ast::Item>) -> P<ast::Item> {
    // we replace the input function with a function that instead compiles the
    // pretty printed original to a pexe and invokes chrome to simulate being
    // embedding in a website.

    println!("============");
    println!("{:?}", item);

    #[derive(PartialEq)]
    enum HasTestSignature {
        Yes,
        No,
        NotEvenAFunction,
    }

    fn has_correct_signature(i: &ast::Item) -> HasTestSignature {
        match &i.node {
          &ast::ItemFn(ref decl, _, _, ref generics, _) => {
            let no_output = match decl.output {
                ast::DefaultReturn(..) => true,
                _ => false
            };
            if decl.inputs.len() == 2
                   && no_output
                   && !generics.is_parameterized() {
                HasTestSignature::Yes
            } else {
                HasTestSignature::No
            }
          }
          _ => HasTestSignature::NotEvenAFunction,
        }
    }

    // first check that the annotated item is, in fact, a function:
    match has_correct_signature(&*item) {
        HasTestSignature::Yes => { println!("sig is fine"); },
        HasTestSignature::No => {
            ecx.span_err(sp, "function must be typed: fn(instance: \
                         ppapi::Instance, args: HashMap<String, String>) -> ()");
            return item;
        },
        HasTestSignature::NotEvenAFunction => {
            ecx.span_err(sp, "must be a function: fn(instance: ppapi::Instance, \
                         args: HashMap<String, String>) -> ()");
            return item;
        },
    }

    let test_name = item.ident;
    let wrapper =
        quote_item!(
            ecx,
            #![no_main]
            extern crate ppapi;

            use std::collections::HashMap;

            struct ResultMessager(ppapi::Messaging);
            impl Drop for ResultMessager {
                fn drop(&mut self) {
                    use std::rt::unwind::panicking;
                    let &mut ResultMessager(msg) = self;

                    if panicking() {
                        msg.post_message("failure");
                    } else {
                        msg.post_message("success");
                    }
                }
            }

            $item

            #[no_mangle] pub extern fn ppapi_instance_created(instance: ppapi::Instance,
                                                              args: HashMap<String, String>) {
                use ppapi::MessageLoop;
                assert!(MessageLoop::post_to_self(move |: _| {
                    let result = ResultMessager(instance.messaging());
                    $test_name(instance.clone(), args.clone());
                }).is_ok());
                assert!(MessageLoop::current().unwrap().shutdown().is_ok());
            }
            #[no_mangle] pub extern fn ppapi_instance_destroyed() { }
            );
    let wrapper = wrapper.expect("the wrapper failed to quote");
    let wrapper_ident = intern_and_get_ident(wrapper.to_source().as_slice());
    let wrapper_str = ecx.expr_str(sp, wrapper_ident);

    let cwd = ::std::os::getcwd().unwrap();
    let deps_str = cwd.join_many(["target", "le32-unknown-nacl", "deps"].as_slice())
        .display().to_string();
    let deps_ident = intern_and_get_ident(deps_str.as_slice());
    let deps_dir = ecx.expr_str(codemap::DUMMY_SP, deps_ident);

    let timeout = None::<u64>;

    let host_test =
        quote_item!(
            ecx,
            #[test] fn $test_name() {
                use std::io::TempDir;
                use std::io::fs::File;
                use std::io::{Command, LineBufferedWriter};
                use std::io::process::{ProcessExit, ProcessOutput};
                use std::io::stdio::{stdout, stderr, StdWriter};

                // the source to the real test:
                const REAL_TEST: &'static str = $wrapper_str;

                let tmp = TempDir::new(stringify!($test_name))
                    .ok().expect("need temp directory for test artifacts");

                let url = format!("file://{}",
                                  tmp.path().join("index.html").display());
                let chrome_args = ["--allow-file-access-from-files".to_string(),
                                   "--bwsi".to_string(),
                                   "--no-sandbox".to_string(),
                                   "--silent-launch".to_string(),
                                   "--noerrdialogs".to_string(),
                                   "--no-first-run".to_string(),
                                   "--no-default-browser-check".to_string(),
                                   url];

                let stdout_path = tmp.path().join("stdout");
                let stdout_name = stdout_path
                    .display().to_string();
                let stderr_path = tmp.path().join("stderr");
                let stderr_name = stderr_path
                    .display().to_string();
                let chrome_env = [("NACL_EXE_STDOUT".to_string(), stdout_name),
                                  ("NACL_EXE_STDERR".to_string(), stderr_name)];

                let rustc_args = ["-".to_string(),
                                  "-o".to_string(),
                                  tmp.path().join("test-main.pexe").display().to_string(),
                                  "--crate-type".to_string(), "bin".to_string(),
                                  "--target".to_string(),
                                  "le32-unknown-nacl".to_string(),
                                  "-L".to_string(),
                                  ($deps_dir).to_string()];
                let mut rustc = Command::new("rustc");
                rustc.args(rustc_args);
                println!("∨∨∨∨∨∨∨∨∨∨∨    rustc    ∨∨∨∨∨∨∨∨∨∨∨");
                println!("spawning `{:?}`", rustc);
                let mut rustc = rustc.spawn().unwrap();
                rustc.stdin
                    .as_mut()
                    .unwrap()
                    .write_str(REAL_TEST)
                    .unwrap();

                {
                    let path = tmp.path()
                        .join("index.html");
                    let file = File::create(&path).unwrap();
                    file.write_str($HTML).unwrap();
                }
                {
                    let path = tmp.path()
                        .join("manifest.nmf");
                    let file = File::create(&path).unwrap();
                    file.write_str($MANIFEST).unwrap();
                }

                match rustc.wait_with_output() {
                    Ok(ProcessOutput {
                        status: exit_status,
                        output: out, error: err,
                    }) => {
                        stdout().write(out.as_slice());
                        stderr().write(err.as_slice());
                        assert!(exit_status.success());
                    }
                    err => { err.unwrap(); },
                }
                println!("∧∧∧∧∧∧∧∧∧∧∧    rustc    ∧∧∧∧∧∧∧∧∧∧∧");

                let mut chrome = Command::new("google-chrome");
                chrome.args(chrome_args);
                for (k, v) in chrome_env.iter() {
                    chrome.env(k, v);
                }
                println!("∨∨∨∨∨∨∨∨∨∨∨   chrome    ∨∨∨∨∨∨∨∨∨∨∨");
                println!("spawning `{:?}`:", chrome);

                let mut chrome = chrome.spawn().unwrap();
                chrome.set_timeout($timeout);

                fn split_and_print(where_: LineBufferedWriter<StdWriter>,
                                   kind: &'static str, out: &[u8]) {
                    for line in out.split(move |: v| v == '\n' ) {
                        where_.write_str(kind).unwrap();
                        where_.write(line).unwrap();
                        where_.write_u8('\n').unwrap();
                    }
                }

                fn dump_output(cmd: &mut Process) {
                    let output = cmd.stdout
                        .as_mut().unwrap()
                        .read_to_end().unwrap();
                    let error = cmd.stderr
                        .as_mut().unwrap()
                        .read_to_end().unwrap();
                    split_and_print(stdout(), "stdout: ", output.as_slice());
                    split_and_print(stderr(), "stderr: ", error.as_slice());
                }

                match chrome.wait() {
                    Ok(status) => {
                        dump_output(&mut chrome);
                        assert!(status.success());
                    },
                    Err(IoError { kind: IoErrorKind::TimedOut, .. }) => {
                        println!("timeout! sending sigterm...");
                        chrome.set_timeout(Some(6000));
                        chrome.signal_exit().unwrap();
                        let res = chrome.wait();
                        let res = match res {
                            Err(IoError { kind: IoErrorKind::TimedOut, .. }) => {
                                println!("1s later: chrome still hasn't quit; killing.");
                                chrome.signal_kill().unwrap();
                                chrome.wait()
                            },
                            res => res,
                        }
                        dump_output(&mut chrome);
                        assert_eq!(res, Ok(ProcessExit::ExitStatus(0))); // always false.
                        unreachable!()
                    },
                    res => {
                        dump_output(&mut chrome);
                        res.unwrap();
                        unreachable!()
                    }
                }
                println!("∧∧∧∧∧∧∧∧∧∧∧   chrome    ∧∧∧∧∧∧∧∧∧∧∧");

                println!("∨∨∨∨∨∨∨∨∨∨∨ test output ∨∨∨∨∨∨∨∨∨∨∨");
                fn read_log(p: &Path) -> Vec<u8> {
                    let f = File::open(p).unwrap();
                    f.read_to_end().unwrap()
                }
                let test_stdout = read_log(&stdout_path);
                let test_stderr = read_log(&stderr_path);
                split_and_print(stdout(), "test stdout: ", test_stdout.as_slice());
                split_and_print(stderr(), "test stderr: ", test_stderr.as_slice());
                println!("∧∧∧∧∧∧∧∧∧∧∧ test output ∧∧∧∧∧∧∧∧∧∧∧");
            });
    host_test.unwrap()
}
<|endoftext|>


<commit_before>use node;
use time;
use std::collections::VecDeque;
use node::receptions;

pub const POLL_FREQUENCY_MS: u64 = 50;
pub const TRIES: u8 = 5;

#[test]
fn node_ping() {
   let alpha = node::Node::new();
   let beta  = node::Node::new();
   let beta_seed = beta.local_info();
   let span = time::Duration::seconds(1);

   // Bootstrapping alpha:
   alpha.bootstrap(beta_seed);

   let beta_receptions = alpha.receptions().during(span).from(beta.id().clone());

   // Alpha pings beta.
   assert_eq!(alpha.ping(beta.resources.id.clone()), node::PingResult::Alive);
   assert_eq!(1, beta_receptions.count());
}

#[test]
fn reception_iterator_times_out_correctly() {
   let alpha = node::Node::new();
   let span = time::Duration::seconds(1);
   let maximum = time::Duration::seconds(3);
   let receptions = alpha.receptions().during(span);

   let before = time::SteadyTime::now();

   // nothing is happening, so this should time out in around a second (not necessarily precise)
   assert_eq!(0, receptions.count());

   let after = time::SteadyTime::now();

   assert!(after - before < maximum);
}

#[test]
fn chained_node_find() {
   let mut nodes: VecDeque<node::Node> = (0..10).map(|_| { node::Node::new() }).collect();

   // We inform each node of the existance of the next three.
   for i in 1..4 {
      for (alpha, beta) in nodes.iter().zip(nodes.iter().skip(i)) {
         alpha.resources.table.insert_node(beta.local_info());
      }
   }

   // Head finds tail
   let head = nodes.pop_front().unwrap();
   let tail = nodes.pop_back().unwrap();
   assert_eq!(head.find_node(tail.id()).unwrap(), tail.local_info());
}

#[test]
fn bootstrapping_and_finding_on_simulated_network() {
   let origin = node::Node::new();

   let mut nodes: VecDeque<node::Node> = (0..100).map(|_| { node::Node::new() }).collect();

   for node in nodes.iter() {
      node.bootstrap(origin.local_info());
   }

   // Head finds tail in a few steps.
   let head = nodes.pop_front().unwrap();
   let tail = nodes.pop_back().unwrap();

   let receptions =
      head.receptions()
          .during(time::Duration::seconds(3))
          .rpc(receptions::RpcFilter::FindNodeResponse);

   assert_eq!(head.find_node(tail.id()).unwrap().id, tail.local_info().id);
   let maximum_steps = 10;
   assert!(receptions.count() < maximum_steps);
}
<commit_msg>Relaxed test timing<commit_after>use node;
use time;
use std::collections::VecDeque;
use node::receptions;

pub const POLL_FREQUENCY_MS: u64 = 50;
pub const TRIES: u8 = 5;

#[test]
fn node_ping() {
   let alpha = node::Node::new();
   let beta  = node::Node::new();
   let beta_seed = beta.local_info();
   let span = time::Duration::seconds(1);

   // Bootstrapping alpha:
   alpha.bootstrap(beta_seed);

   let beta_receptions = alpha.receptions().during(span).from(beta.id().clone());

   // Alpha pings beta.
   assert_eq!(alpha.ping(beta.resources.id.clone()), node::PingResult::Alive);
   assert_eq!(1, beta_receptions.count());
}

#[test]
fn reception_iterator_times_out_correctly() {
   let alpha = node::Node::new();
   let span = time::Duration::seconds(1);
   let maximum = time::Duration::seconds(3);
   let receptions = alpha.receptions().during(span);

   let before = time::SteadyTime::now();

   // nothing is happening, so this should time out in around a second (not necessarily precise)
   assert_eq!(0, receptions.count());

   let after = time::SteadyTime::now();

   assert!(after - before < maximum);
}

#[test]
fn chained_node_find() {
   let mut nodes: VecDeque<node::Node> = (0..10).map(|_| { node::Node::new() }).collect();

   // We inform each node of the existance of the next three.
   for i in 1..4 {
      for (alpha, beta) in nodes.iter().zip(nodes.iter().skip(i)) {
         alpha.resources.table.insert_node(beta.local_info());
      }
   }

   // Head finds tail
   let head = nodes.pop_front().unwrap();
   let tail = nodes.pop_back().unwrap();
   assert_eq!(head.find_node(tail.id()).unwrap(), tail.local_info());
}

#[test]
fn bootstrapping_and_finding_on_simulated_network() {
   let origin = node::Node::new();

   let mut nodes: VecDeque<node::Node> = (0..100).map(|_| { node::Node::new() }).collect();

   for node in nodes.iter() {
      node.bootstrap(origin.local_info());
   }

   // Head finds tail in a few steps.
   let head = nodes.pop_front().unwrap();
   let tail = nodes.pop_back().unwrap();

   let receptions =
      head.receptions()
          .during(time::Duration::seconds(1))
          .rpc(receptions::RpcFilter::FindNodeResponse);

   assert_eq!(head.find_node(tail.id()).unwrap().id, tail.local_info().id);
   let maximum_steps = 5;
   assert!(receptions.count() < maximum_steps);
}
<|endoftext|>


<commit_before>#![crate_type = "bin"]
#![feature(collections)]

extern crate gtk;
extern crate glib;
extern crate sysinfo;

use gtk::{WindowTrait, ContainerTrait, WidgetTrait, ButtonSignals, BoxTrait};
use gtk::{IconSize, Orientation, ReliefStyle};
use sysinfo::*;
use gtk::signal::Inhibit;
use gtk::signal::{WidgetSignals, TreeViewSignals};
use std::collections::VecMap;
use std::str::FromStr;
use std::rc::Rc;
use std::cell::{RefCell, RefMut};
use std::ops::DerefMut;

struct NoteBook {
    notebook: gtk::NoteBook,
    tabs: Vec<gtk::Box>
}

impl NoteBook {
    fn new() -> NoteBook {
        NoteBook {
            notebook: gtk::NoteBook::new().unwrap(),
            tabs: Vec::new()
        }
    }

    fn create_tab<'a, Widget: gtk::WidgetTrait>(&mut self, title: &'a str, widget: &Widget) -> Option<u32> {
        let label = gtk::Label::new(title).unwrap();
        let tab = gtk::Box::new(Orientation::Horizontal, 0).unwrap();

        tab.pack_start(&label, false, false, 0);
        tab.show_all();

        let index = match self.notebook.append_page(widget, Some(&tab)) {
            Some(index) => index,
            _ => return None
        };

        self.tabs.push(tab);

        Some(index)
    }
}

struct Procs {
    left_tree: gtk::TreeView,
    scroll: gtk::ScrolledWindow,
    current_pid: Rc<RefCell<Option<String>>>,
    kill_button: Rc<RefCell<gtk::Button>>,
    vertical_layout: gtk::Box,
    list_store: gtk::ListStore
}

impl Procs {
    pub fn new<'a>(proc_list: &VecMap<Processus>) -> Procs {
        let mut left_tree = gtk::TreeView::new().unwrap();
        let mut scroll = gtk::ScrolledWindow::new(None, None).unwrap();
        let mut current_pid = Rc::new(RefCell::new(None));
        let mut kill_button = Rc::new(RefCell::new(gtk::Button::new_with_label("End task").unwrap()));
        let mut current_pid1 = current_pid.clone();
        let mut current_pid2 = current_pid.clone();
        let mut kill_button1 = kill_button.clone();

        scroll.set_min_content_height(800);
        scroll.set_min_content_width(600);

        let mut columns : Vec<gtk::TreeViewColumn> = Vec::new();

        append_column("pid", &mut columns);
        append_column("process name", &mut columns);
        append_column("cpu usage", &mut columns);
        append_column("memory usage", &mut columns);

        for i in columns {
            left_tree.append_column(&i);
        }

        let mut list_store = gtk::ListStore::new(&[glib::Type::String, glib::Type::String, glib::Type::String, glib::Type::String]).unwrap();
        for (_, pro) in proc_list {
            create_and_fill_model(&mut list_store, pro.pid, &pro.name, pro.cpu_usage, pro.memory);
        }

        left_tree.set_model(&list_store.get_model().unwrap());
        left_tree.set_headers_visible(true);
        scroll.add(&left_tree);
        let mut vertical_layout = gtk::Box::new(gtk::Orientation::Vertical, 0).unwrap();

        left_tree.connect_cursor_changed(move |tree_view| {
            match tree_view.get_selection() {
                Some(selection) => {
                    let model = tree_view.get_model().unwrap();
                    let mut iter = gtk::TreeIter::new();

                    if selection.get_selected(&model, &mut iter) {
                        let pid = model.get_value(&iter, 0).get_string();
                        let mut tmp = current_pid1.borrow_mut();
                        *tmp = pid;
                    }
                    (*kill_button1.borrow_mut()).set_sensitive((*current_pid.borrow()).is_some());
                }
                None => {
                    let mut tmp = current_pid1.borrow_mut();
                    *tmp = None;
                }
            }
        });
        (*kill_button.borrow_mut()).set_sensitive(false);

        vertical_layout.add(&scroll);
        vertical_layout.add(&(*kill_button.borrow_mut()));
        Procs {
            left_tree: left_tree,
            scroll: scroll,
            current_pid: current_pid2.clone(),
            kill_button: kill_button,
            vertical_layout: vertical_layout,
            list_store: list_store
        }
    }
}

fn append_column(title: &str, v: &mut Vec<gtk::TreeViewColumn>) {
    let l = v.len();
    let renderer = gtk::CellRendererText::new().unwrap();

    v.push(gtk::TreeViewColumn::new().unwrap());
    let tmp = v.get_mut(l).unwrap();

    tmp.set_title(title);
    tmp.pack_start(&renderer, true);
    tmp.add_attribute(&renderer, "text", l as i32);
}

fn create_and_fill_model(list_store: &mut gtk::ListStore, pid: i64, name: &str, cpu: f32, memory: u64) {
    if name.len() < 1 {
        return;
    }
    let mut top_level = gtk::TreeIter::new();

    list_store.append(&mut top_level);
    list_store.set_string(&top_level, 0, &format!("{}", pid));
    list_store.set_string(&top_level, 1, name);
    list_store.set_string(&top_level, 2, &format!("{}", cpu));
    list_store.set_string(&top_level, 3, &format!("{}", memory));
}

fn update_window(w: &mut (&mut gtk::ListStore, Rc<RefCell<sysinfo::System>>, Rc<RefCell<DisplaySysInfo>>)) -> i32 {
    let mut model = w.0.get_model().unwrap();
    let mut iter = gtk::TreeIter::new();

    (*w.1.borrow_mut()).refresh();
    let mut entries : VecMap<Processus> = ((*w.1.borrow()).get_processus_list()).clone();
    let mut nb = model.iter_n_children(None);

    let sys = w.1.clone();
    (*w.2.borrow_mut()).update_ram_display(sys.clone());
    (*w.2.borrow_mut()).update_process_display(sys);

    let mut i = 0;
    while i < nb {
        if model.iter_nth_child(&mut iter, None, i) {
            let pid : i64 = i64::from_str(&model.get_value(&iter, 0).get_string().unwrap()).unwrap();
            let mut to_delete = false;

            match entries.get(&(pid as usize)) {
                Some(p) => {
                    //w.0.set_string(&iter, 1, &p.name);
                    w.0.set_string(&iter, 2, &format!("{}", p.cpu_usage));
                    w.0.set_string(&iter, 3, &format!("{}", p.memory));
                    to_delete = true;
                }
                None => {
                    w.0.remove(&iter);
                }
            }
            if to_delete {
                entries.remove(&(pid as usize));
                nb = model.iter_n_children(None);
                i += 1;
            }
        } else {
            i += 1;
        }
    }
    for (_, pro) in entries {
        create_and_fill_model(&mut w.0, pro.pid, &pro.name, pro.cpu_usage, pro.memory);
    }
    1
}

struct DisplaySysInfo {
    procs : Rc<RefCell<Vec<gtk::ProgressBar>>>,
    ram : Rc<RefCell<gtk::ProgressBar>>,
    swap : Rc<RefCell<gtk::ProgressBar>>,
    vertical_layout : gtk::Box
}

impl DisplaySysInfo {
    pub fn new(sys1: Rc<RefCell<sysinfo::System>>) -> DisplaySysInfo {
        let mut tmp = DisplaySysInfo {
            procs: Rc::new(RefCell::new(Vec::new())),
            ram: Rc::new(RefCell::new(gtk::ProgressBar::new().unwrap())),
            swap: Rc::new(RefCell::new(gtk::ProgressBar::new().unwrap())),
            vertical_layout: gtk::Box::new(gtk::Orientation::Vertical, 0).unwrap()
        };

        let sys2 = sys1.clone();
        let mut v = tmp.procs.clone();

        (*tmp.ram.borrow_mut()).set_show_text(true);
        (*tmp.swap.borrow_mut()).set_show_text(true);

        tmp.vertical_layout.set_spacing(5);
        let mut i = 0;
        let mut total = false;

        tmp.vertical_layout.pack_start(&gtk::Label::new("Memory usage").unwrap(), false, false, 15);
        tmp.vertical_layout.add(&(*tmp.ram.borrow()));
        tmp.vertical_layout.pack_start(&gtk::Label::new("Swap usage").unwrap(), false, false, 15);
        tmp.vertical_layout.add(&(*tmp.swap.borrow()));
        tmp.vertical_layout.pack_start(&gtk::Label::new("Total CPU usage").unwrap(), false, false, 15);
        for pro in (*sys1.borrow()).get_process_list() {
            if total {
                (*v.borrow_mut()).push(gtk::ProgressBar::new().unwrap());
                let p : &gtk::ProgressBar = &(*v.borrow())[i];
                let l = gtk::Label::new(&format!("{}", i)).unwrap();
                let horizontal_layout = gtk::Box::new(gtk::Orientation::Horizontal, 0).unwrap();

                p.set_text(&format!("{:.2} %", pro.get_cpu_usage() * 100.));
                p.set_show_text(true);
                p.set_fraction(pro.get_cpu_usage() as f64);
                horizontal_layout.pack_start(&l, false, false, 5);
                horizontal_layout.pack_start(p, true, true, 5);
                tmp.vertical_layout.add(&horizontal_layout);
            } else {
                (*v.borrow_mut()).push(gtk::ProgressBar::new().unwrap());
                let p : &gtk::ProgressBar = &(*v.borrow())[i];

                p.set_text(&format!("{:.2} %", pro.get_cpu_usage() * 100.));
                p.set_show_text(true);
                p.set_fraction(pro.get_cpu_usage() as f64);

                tmp.vertical_layout.add(p);
                tmp.vertical_layout.pack_start(&gtk::Label::new("Process usage").unwrap(), false, false, 15);
                total = true;
            }
            i += 1;
        }
        tmp.update_ram_display(sys2);
        tmp
    }

    pub fn update_ram_display(&mut self, sys: Rc<RefCell<sysinfo::System>>) {
        let total = (*sys.borrow()).get_total_memory();
        let used = (*sys.borrow()).get_free_memory();
        let disp = if total < 100000 {
            format!("{} / {}B", used, total)
        } else if total < 10000000 {
            format!("{} / {}KB", used / 1000, total / 1000)
        } else if total < 10000000000 {
            format!("{} / {}MB", used / 1000000, total / 1000000)
        } else {
            format!("{} / {}GB", used / 1000000000, total / 1000000000)
        };

        (*self.ram.borrow_mut()).set_text(&disp);
        (*self.ram.borrow_mut()).set_fraction(used as f64 / total as f64);

        let total = (*sys.borrow()).get_total_swap();
        let used = total - (*sys.borrow()).get_free_swap();
        let disp = if total < 100000 {
            format!("{} / {}B", used, total)
        } else if total < 10000000 {
            format!("{} / {}KB", used / 1000, total / 1000)
        } else if total < 10000000000 {
            format!("{} / {}MB", used / 1000000, total / 1000000)
        } else {
            format!("{} / {}GB", used / 1000000000, total / 1000000000)
        };

        (*self.swap.borrow_mut()).set_text(&disp);
        (*self.swap.borrow_mut()).set_fraction(used as f64 / total as f64);
    }

    pub fn update_process_display(&mut self, sys: Rc<RefCell<sysinfo::System>>) {
        let v = &*self.procs.borrow_mut();
        let mut total = false;
        let mut i = 0;
        for pro in (*sys.borrow()).get_process_list() {
            v[i].set_text(&format!("{:.1} %", pro.get_cpu_usage() * 100.));
            v[i].set_show_text(true);
            v[i].set_fraction(pro.get_cpu_usage() as f64);
            i += 1;
        }
    }
}

fn main() {
    gtk::init();

    let mut window = gtk::Window::new(gtk::WindowType::TopLevel).unwrap();
    let mut sys : Rc<RefCell<sysinfo::System>> = Rc::new(RefCell::new(sysinfo::System::new()));
    let mut note = NoteBook::new();
    (*sys.borrow_mut()).refresh();
    let mut procs = Procs::new((*sys.borrow()).get_processus_list());
    let mut current_pid2 = procs.current_pid.clone();
    let mut sys1 = sys.clone();
    let mut sys2 = sys.clone();

    window.set_title("Processus viewer");
    window.set_window_position(gtk::WindowPosition::Center);

    window.connect_delete_event(|_, _| {
        gtk::main_quit();
        Inhibit(true)
    });

    (*procs.kill_button.borrow_mut()).connect_clicked(move |_| {
        let tmp = (*current_pid2.borrow_mut()).is_some() ;

        if tmp {
            let s = (*current_pid2.borrow()).clone();
            match (*sys.borrow_mut()).get_processus(i64::from_str(&s.unwrap()).unwrap()) {
                Some(p) => {
                    p.kill(Signal::Kill);
                },
                None => {}
            };
        }
    });

    let mut display_tab = Rc::new(RefCell::new(DisplaySysInfo::new(sys2)));

    glib::timeout::add(1500, update_window, &mut (&mut procs.list_store, sys1.clone(), display_tab.clone()));
    //window.add(&vertical_layout);
    note.create_tab("Processus list", &procs.vertical_layout);
    //let t = gtk::Button::new_with_label("test").unwrap();
    note.create_tab("System usage", &(*display_tab.borrow()).vertical_layout);
    window.add(&note.notebook);
    window.show_all();
    gtk::main();
}
<commit_msg>Remove warnings<commit_after>#![crate_type = "bin"]
#![feature(collections)]

extern crate gtk;
extern crate glib;
extern crate sysinfo;

use gtk::{WindowTrait, ContainerTrait, WidgetTrait, ButtonSignals, BoxTrait};
use gtk::{Orientation};
use sysinfo::*;
use gtk::signal::Inhibit;
use gtk::signal::{WidgetSignals, TreeViewSignals};
use std::collections::VecMap;
use std::str::FromStr;
use std::rc::Rc;
use std::cell::{RefCell};

struct NoteBook {
    notebook: gtk::NoteBook,
    tabs: Vec<gtk::Box>
}

impl NoteBook {
    fn new() -> NoteBook {
        NoteBook {
            notebook: gtk::NoteBook::new().unwrap(),
            tabs: Vec::new()
        }
    }

    fn create_tab<'a, Widget: gtk::WidgetTrait>(&mut self, title: &'a str, widget: &Widget) -> Option<u32> {
        let label = gtk::Label::new(title).unwrap();
        let tab = gtk::Box::new(Orientation::Horizontal, 0).unwrap();

        tab.pack_start(&label, false, false, 0);
        tab.show_all();

        let index = match self.notebook.append_page(widget, Some(&tab)) {
            Some(index) => index,
            _ => return None
        };

        self.tabs.push(tab);

        Some(index)
    }
}

struct Procs {
    left_tree: gtk::TreeView,
    scroll: gtk::ScrolledWindow,
    current_pid: Rc<RefCell<Option<String>>>,
    kill_button: Rc<RefCell<gtk::Button>>,
    vertical_layout: gtk::Box,
    list_store: gtk::ListStore
}

impl Procs {
    pub fn new<'a>(proc_list: &VecMap<Processus>) -> Procs {
        let left_tree = gtk::TreeView::new().unwrap();
        let scroll = gtk::ScrolledWindow::new(None, None).unwrap();
        let current_pid = Rc::new(RefCell::new(None));
        let kill_button = Rc::new(RefCell::new(gtk::Button::new_with_label("End task").unwrap()));
        let current_pid1 = current_pid.clone();
        let current_pid2 = current_pid.clone();
        let kill_button1 = kill_button.clone();

        scroll.set_min_content_height(800);
        scroll.set_min_content_width(600);

        let mut columns : Vec<gtk::TreeViewColumn> = Vec::new();

        append_column("pid", &mut columns);
        append_column("process name", &mut columns);
        append_column("cpu usage", &mut columns);
        append_column("memory usage", &mut columns);

        for i in columns {
            left_tree.append_column(&i);
        }

        let mut list_store = gtk::ListStore::new(&[glib::Type::String, glib::Type::String, glib::Type::String, glib::Type::String]).unwrap();
        for (_, pro) in proc_list {
            create_and_fill_model(&mut list_store, pro.pid, &pro.name, pro.cpu_usage, pro.memory);
        }

        left_tree.set_model(&list_store.get_model().unwrap());
        left_tree.set_headers_visible(true);
        scroll.add(&left_tree);
        let vertical_layout = gtk::Box::new(gtk::Orientation::Vertical, 0).unwrap();

        left_tree.connect_cursor_changed(move |tree_view| {
            match tree_view.get_selection() {
                Some(selection) => {
                    let model = tree_view.get_model().unwrap();
                    let mut iter = gtk::TreeIter::new();

                    if selection.get_selected(&model, &mut iter) {
                        let pid = model.get_value(&iter, 0).get_string();
                        let mut tmp = current_pid1.borrow_mut();
                        *tmp = pid;
                    }
                    (*kill_button1.borrow_mut()).set_sensitive((*current_pid.borrow()).is_some());
                }
                None => {
                    let mut tmp = current_pid1.borrow_mut();
                    *tmp = None;
                }
            }
        });
        (*kill_button.borrow_mut()).set_sensitive(false);

        vertical_layout.add(&scroll);
        vertical_layout.add(&(*kill_button.borrow_mut()));
        Procs {
            left_tree: left_tree,
            scroll: scroll,
            current_pid: current_pid2.clone(),
            kill_button: kill_button,
            vertical_layout: vertical_layout,
            list_store: list_store
        }
    }
}

fn append_column(title: &str, v: &mut Vec<gtk::TreeViewColumn>) {
    let l = v.len();
    let renderer = gtk::CellRendererText::new().unwrap();

    v.push(gtk::TreeViewColumn::new().unwrap());
    let tmp = v.get_mut(l).unwrap();

    tmp.set_title(title);
    tmp.pack_start(&renderer, true);
    tmp.add_attribute(&renderer, "text", l as i32);
}

fn create_and_fill_model(list_store: &mut gtk::ListStore, pid: i64, name: &str, cpu: f32, memory: u64) {
    if name.len() < 1 {
        return;
    }
    let mut top_level = gtk::TreeIter::new();

    list_store.append(&mut top_level);
    list_store.set_string(&top_level, 0, &format!("{}", pid));
    list_store.set_string(&top_level, 1, name);
    list_store.set_string(&top_level, 2, &format!("{}", cpu));
    list_store.set_string(&top_level, 3, &format!("{}", memory));
}

fn update_window(w: &mut (&mut gtk::ListStore, Rc<RefCell<sysinfo::System>>, Rc<RefCell<DisplaySysInfo>>)) -> i32 {
    let model = w.0.get_model().unwrap();
    let mut iter = gtk::TreeIter::new();

    (*w.1.borrow_mut()).refresh();
    let mut entries : VecMap<Processus> = ((*w.1.borrow()).get_processus_list()).clone();
    let mut nb = model.iter_n_children(None);

    let sys = w.1.clone();
    (*w.2.borrow_mut()).update_ram_display(sys.clone());
    (*w.2.borrow_mut()).update_process_display(sys);

    let mut i = 0;
    while i < nb {
        if model.iter_nth_child(&mut iter, None, i) {
            let pid : i64 = i64::from_str(&model.get_value(&iter, 0).get_string().unwrap()).unwrap();
            let mut to_delete = false;

            match entries.get(&(pid as usize)) {
                Some(p) => {
                    //w.0.set_string(&iter, 1, &p.name);
                    w.0.set_string(&iter, 2, &format!("{}", p.cpu_usage));
                    w.0.set_string(&iter, 3, &format!("{}", p.memory));
                    to_delete = true;
                }
                None => {
                    w.0.remove(&iter);
                }
            }
            if to_delete {
                entries.remove(&(pid as usize));
                nb = model.iter_n_children(None);
                i += 1;
            }
        } else {
            i += 1;
        }
    }
    for (_, pro) in entries {
        create_and_fill_model(&mut w.0, pro.pid, &pro.name, pro.cpu_usage, pro.memory);
    }
    1
}

struct DisplaySysInfo {
    procs : Rc<RefCell<Vec<gtk::ProgressBar>>>,
    ram : Rc<RefCell<gtk::ProgressBar>>,
    swap : Rc<RefCell<gtk::ProgressBar>>,
    vertical_layout : gtk::Box
}

impl DisplaySysInfo {
    pub fn new(sys1: Rc<RefCell<sysinfo::System>>) -> DisplaySysInfo {
        let mut tmp = DisplaySysInfo {
            procs: Rc::new(RefCell::new(Vec::new())),
            ram: Rc::new(RefCell::new(gtk::ProgressBar::new().unwrap())),
            swap: Rc::new(RefCell::new(gtk::ProgressBar::new().unwrap())),
            vertical_layout: gtk::Box::new(gtk::Orientation::Vertical, 0).unwrap()
        };

        let sys2 = sys1.clone();
        let v = tmp.procs.clone();

        (*tmp.ram.borrow_mut()).set_show_text(true);
        (*tmp.swap.borrow_mut()).set_show_text(true);

        tmp.vertical_layout.set_spacing(5);
        let mut i = 0;
        let mut total = false;

        tmp.vertical_layout.pack_start(&gtk::Label::new("Memory usage").unwrap(), false, false, 15);
        tmp.vertical_layout.add(&(*tmp.ram.borrow()));
        tmp.vertical_layout.pack_start(&gtk::Label::new("Swap usage").unwrap(), false, false, 15);
        tmp.vertical_layout.add(&(*tmp.swap.borrow()));
        tmp.vertical_layout.pack_start(&gtk::Label::new("Total CPU usage").unwrap(), false, false, 15);
        for pro in (*sys1.borrow()).get_process_list() {
            if total {
                (*v.borrow_mut()).push(gtk::ProgressBar::new().unwrap());
                let p : &gtk::ProgressBar = &(*v.borrow())[i];
                let l = gtk::Label::new(&format!("{}", i)).unwrap();
                let horizontal_layout = gtk::Box::new(gtk::Orientation::Horizontal, 0).unwrap();

                p.set_text(&format!("{:.2} %", pro.get_cpu_usage() * 100.));
                p.set_show_text(true);
                p.set_fraction(pro.get_cpu_usage() as f64);
                horizontal_layout.pack_start(&l, false, false, 5);
                horizontal_layout.pack_start(p, true, true, 5);
                tmp.vertical_layout.add(&horizontal_layout);
            } else {
                (*v.borrow_mut()).push(gtk::ProgressBar::new().unwrap());
                let p : &gtk::ProgressBar = &(*v.borrow())[i];

                p.set_text(&format!("{:.2} %", pro.get_cpu_usage() * 100.));
                p.set_show_text(true);
                p.set_fraction(pro.get_cpu_usage() as f64);

                tmp.vertical_layout.add(p);
                tmp.vertical_layout.pack_start(&gtk::Label::new("Process usage").unwrap(), false, false, 15);
                total = true;
            }
            i += 1;
        }
        tmp.update_ram_display(sys2);
        tmp
    }

    pub fn update_ram_display(&mut self, sys: Rc<RefCell<sysinfo::System>>) {
        let total = (*sys.borrow()).get_total_memory();
        let used = (*sys.borrow()).get_free_memory();
        let disp = if total < 100000 {
            format!("{} / {}B", used, total)
        } else if total < 10000000 {
            format!("{} / {}KB", used / 1000, total / 1000)
        } else if total < 10000000000 {
            format!("{} / {}MB", used / 1000000, total / 1000000)
        } else {
            format!("{} / {}GB", used / 1000000000, total / 1000000000)
        };

        (*self.ram.borrow_mut()).set_text(&disp);
        (*self.ram.borrow_mut()).set_fraction(used as f64 / total as f64);

        let total = (*sys.borrow()).get_total_swap();
        let used = total - (*sys.borrow()).get_free_swap();
        let disp = if total < 100000 {
            format!("{} / {}B", used, total)
        } else if total < 10000000 {
            format!("{} / {}KB", used / 1000, total / 1000)
        } else if total < 10000000000 {
            format!("{} / {}MB", used / 1000000, total / 1000000)
        } else {
            format!("{} / {}GB", used / 1000000000, total / 1000000000)
        };

        (*self.swap.borrow_mut()).set_text(&disp);
        (*self.swap.borrow_mut()).set_fraction(used as f64 / total as f64);
    }

    pub fn update_process_display(&mut self, sys: Rc<RefCell<sysinfo::System>>) {
        let v = &*self.procs.borrow_mut();
        let mut i = 0;

        for pro in (*sys.borrow()).get_process_list() {
            v[i].set_text(&format!("{:.1} %", pro.get_cpu_usage() * 100.));
            v[i].set_show_text(true);
            v[i].set_fraction(pro.get_cpu_usage() as f64);
            i += 1;
        }
    }
}

fn main() {
    gtk::init();

    let window = gtk::Window::new(gtk::WindowType::TopLevel).unwrap();
    let sys : Rc<RefCell<sysinfo::System>> = Rc::new(RefCell::new(sysinfo::System::new()));
    let mut note = NoteBook::new();
    (*sys.borrow_mut()).refresh();
    let mut procs = Procs::new((*sys.borrow()).get_processus_list());
    let current_pid2 = procs.current_pid.clone();
    let sys1 = sys.clone();
    let sys2 = sys.clone();

    window.set_title("Processus viewer");
    window.set_window_position(gtk::WindowPosition::Center);

    window.connect_delete_event(|_, _| {
        gtk::main_quit();
        Inhibit(true)
    });

    (*procs.kill_button.borrow_mut()).connect_clicked(move |_| {
        let tmp = (*current_pid2.borrow_mut()).is_some() ;

        if tmp {
            let s = (*current_pid2.borrow()).clone();
            match (*sys.borrow_mut()).get_processus(i64::from_str(&s.unwrap()).unwrap()) {
                Some(p) => {
                    p.kill(Signal::Kill);
                },
                None => {}
            };
        }
    });

    let display_tab = Rc::new(RefCell::new(DisplaySysInfo::new(sys2)));

    glib::timeout::add(1500, update_window, &mut (&mut procs.list_store, sys1.clone(), display_tab.clone()));
    //window.add(&vertical_layout);
    note.create_tab("Processus list", &procs.vertical_layout);
    //let t = gtk::Button::new_with_label("test").unwrap();
    note.create_tab("System usage", &(*display_tab.borrow()).vertical_layout);
    window.add(&note.notebook);
    window.show_all();
    gtk::main();
}
<|endoftext|>


<commit_before>use prolog::ast::*;

use std::ops::{Index, IndexMut};
use std::vec::Vec;

#[derive(Clone)]
pub struct Frame {
    pub global_index: usize,
    pub b0: usize,
    pub e: usize,
    pub cp: CodePtr,
    perms: Vec<Addr>
}

impl Frame {
    fn new(global_index: usize, fr: usize, e: usize, cp: CodePtr, n: usize) -> Self {
        Frame {
            global_index,
            b0: 0,
            e: e,
            cp: cp,
            perms: (1 .. n+1).map(|i| Addr::StackCell(fr, i)).collect()
        }
    }
}

pub struct AndStack(Vec<Frame>);

impl AndStack {
    pub fn new() -> Self {
        AndStack(Vec::new())
    }

    pub fn push(&mut self, global_index: usize, e: usize, cp: CodePtr, n: usize) {
        let len = self.0.len();
        self.0.push(Frame::new(global_index, len, e, cp, n));
    }

    #[allow(dead_code)]
    pub fn top(&self) -> Option<&Frame> {
        self.0.last()
    }

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

    pub fn clear(&mut self) {
        self.0.clear()
    }

    pub fn resize(&mut self, fr: usize, n: usize) {
        let len = self[fr].perms.len();

        if len < n {
            self[fr].perms.reserve(n - len);

            for i in len .. n {
                self[fr].perms.push(Addr::StackCell(fr, i));
            }
        }
    }
}

impl Index<usize> for AndStack {
    type Output = Frame;

    fn index(&self, index: usize) -> &Self::Output {
        self.0.index(index)
    }
}

impl IndexMut<usize> for AndStack {
    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
        self.0.index_mut(index)
    }
}

impl Index<usize> for Frame {
    type Output = Addr;

    fn index(&self, index: usize) -> &Self::Output {
        self.perms.index(index - 1)
    }
}

impl IndexMut<usize> for Frame {
    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
        self.perms.index_mut(index - 1)
    }
}
<commit_msg>remove b0 slot from AND stack frames.<commit_after>use prolog::ast::*;

use std::ops::{Index, IndexMut};
use std::vec::Vec;

#[derive(Clone)]
pub struct Frame {
    pub global_index: usize,
    pub e: usize,
    pub cp: CodePtr,
    perms: Vec<Addr>
}

impl Frame {
    fn new(global_index: usize, fr: usize, e: usize, cp: CodePtr, n: usize) -> Self {
        Frame {
            global_index,
            e: e,
            cp: cp,
            perms: (1 .. n+1).map(|i| Addr::StackCell(fr, i)).collect()
        }
    }
}

pub struct AndStack(Vec<Frame>);

impl AndStack {
    pub fn new() -> Self {
        AndStack(Vec::new())
    }

    pub fn push(&mut self, global_index: usize, e: usize, cp: CodePtr, n: usize) {
        let len = self.0.len();
        self.0.push(Frame::new(global_index, len, e, cp, n));
    }

    #[allow(dead_code)]
    pub fn top(&self) -> Option<&Frame> {
        self.0.last()
    }

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

    pub fn clear(&mut self) {
        self.0.clear()
    }

    pub fn resize(&mut self, fr: usize, n: usize) {
        let len = self[fr].perms.len();

        if len < n {
            self[fr].perms.reserve(n - len);

            for i in len .. n {
                self[fr].perms.push(Addr::StackCell(fr, i));
            }
        }
    }
}

impl Index<usize> for AndStack {
    type Output = Frame;

    fn index(&self, index: usize) -> &Self::Output {
        self.0.index(index)
    }
}

impl IndexMut<usize> for AndStack {
    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
        self.0.index_mut(index)
    }
}

impl Index<usize> for Frame {
    type Output = Addr;

    fn index(&self, index: usize) -> &Self::Output {
        self.perms.index(index - 1)
    }
}

impl IndexMut<usize> for Frame {
    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
        self.perms.index_mut(index - 1)
    }
}
<|endoftext|>


<commit_before>use ansi_term::Style;

use fs::{File, FileTarget};

pub use self::cell::{TextCell, TextCellContents, DisplayWidth};
pub use self::colours::Colours;
pub use self::details::Details;
pub use self::grid_details::GridDetails;
pub use self::grid::Grid;
pub use self::lines::Lines;

mod grid;
pub mod details;
mod lines;
mod grid_details;
pub mod column;
mod cell;
mod colours;
mod tree;

pub fn filename(file: &File, colours: &Colours, links: bool, classify: bool) -> TextCellContents {
    let mut bits = Vec::new();

    if file.dir.is_none() {
        if let Some(parent) = file.path.parent() {
            let coconut = parent.components().count();

            if coconut == 1 && parent.has_root() {
                bits.push(colours.symlink_path.paint("/"));
            }
            else if coconut >= 1 {
                bits.push(colours.symlink_path.paint(parent.to_string_lossy().to_string()));
                bits.push(colours.symlink_path.paint("/"));
            }
        }
    }

    if !file.name.is_empty() {
        bits.push(file_colour(colours, file).paint(file.name.clone()));
    }

    if links && file.is_link() {
        match file.link_target() {
            FileTarget::Ok(target) => {
                bits.push(Style::default().paint(" "));
                bits.push(colours.punctuation.paint("->"));
                bits.push(Style::default().paint(" "));

                if target.path.as_os_str() == "/" {
                    // Do nothing when linking to the root directory.
                    // The entirety of the path is the file name!
                }
                else if let Some(parent) = target.path.parent() {
                    let coconut = parent.components().count();

                    if coconut == 1 && parent.has_root() {
                        bits.push(colours.symlink_path.paint("/"));
                    }
                    else if coconut >= 1 {
                        bits.push(colours.symlink_path.paint(parent.to_string_lossy().to_string()));
                        bits.push(colours.symlink_path.paint("/"));
                    }
                }
                else {
                    bits.push(colours.symlink_path.paint("/"));
                }

                if !target.name.is_empty() {
                    bits.push(file_colour(colours, &target).paint(target.name));
                }
            },

            FileTarget::Broken(broken_path) => {
                bits.push(Style::default().paint(" "));
                bits.push(colours.broken_arrow.paint("->"));
                bits.push(Style::default().paint(" "));
                bits.push(colours.broken_filename.paint(broken_path.display().to_string()));
            },

            FileTarget::Err(_) => {
                // Do nothing -- the error gets displayed on the next line
            }
        }
    } else if classify {
        if file.is_executable_file() {
            bits.push(Style::default().paint("*"));
        } else if file.is_directory() {
            bits.push(Style::default().paint("/"));
        } else if file.is_pipe() {
            bits.push(Style::default().paint("|"));
        } else if file.is_link() {
            bits.push(Style::default().paint("@"));
        } else if file.is_socket() {
            bits.push(Style::default().paint("="));
        }
    }

    bits.into()
}

pub fn file_colour(colours: &Colours, file: &File) -> Style {
    match file {
        f if f.is_directory()        => colours.filetypes.directory,
        f if f.is_executable_file()  => colours.filetypes.executable,
        f if f.is_link()             => colours.filetypes.symlink,
        f if f.is_pipe()             => colours.filetypes.pipe,
        f if f.is_char_device()
           | f.is_block_device()     => colours.filetypes.device,
        f if f.is_socket()           => colours.filetypes.socket,
        f if !f.is_file()            => colours.filetypes.special,
        f if f.is_immediate()        => colours.filetypes.immediate,
        f if f.is_image()            => colours.filetypes.image,
        f if f.is_video()            => colours.filetypes.video,
        f if f.is_music()            => colours.filetypes.music,
        f if f.is_lossless()         => colours.filetypes.lossless,
        f if f.is_crypto()           => colours.filetypes.crypto,
        f if f.is_document()         => colours.filetypes.document,
        f if f.is_compressed()       => colours.filetypes.compressed,
        f if f.is_temp()             => colours.filetypes.temp,
        f if f.is_compiled()         => colours.filetypes.compiled,
        _                            => colours.filetypes.normal,
    }
}
<commit_msg>Handle linking to root directories better<commit_after>use ansi_term::Style;

use fs::{File, FileTarget};

pub use self::cell::{TextCell, TextCellContents, DisplayWidth};
pub use self::colours::Colours;
pub use self::details::Details;
pub use self::grid_details::GridDetails;
pub use self::grid::Grid;
pub use self::lines::Lines;

mod grid;
pub mod details;
mod lines;
mod grid_details;
pub mod column;
mod cell;
mod colours;
mod tree;

pub fn filename(file: &File, colours: &Colours, links: bool, classify: bool) -> TextCellContents {
    let mut bits = Vec::new();

    if file.dir.is_none() {
        if let Some(parent) = file.path.parent() {
            let coconut = parent.components().count();

            if coconut == 1 && parent.has_root() {
                bits.push(colours.symlink_path.paint("/"));
            }
            else if coconut >= 1 {
                bits.push(colours.symlink_path.paint(parent.to_string_lossy().to_string()));
                bits.push(colours.symlink_path.paint("/"));
            }
        }
    }

    if !file.name.is_empty() {
        bits.push(file_colour(colours, file).paint(file.name.clone()));
    }

    if links && file.is_link() {
        match file.link_target() {
            FileTarget::Ok(target) => {
                bits.push(Style::default().paint(" "));
                bits.push(colours.punctuation.paint("->"));
                bits.push(Style::default().paint(" "));

                if let Some(parent) = target.path.parent() {
                    let coconut = parent.components().count();

                    if coconut == 1 && parent.has_root() {
                        bits.push(colours.symlink_path.paint("/"));
                    }
                    else if coconut >= 1 {
                        bits.push(colours.symlink_path.paint(parent.to_string_lossy().to_string()));
                        bits.push(colours.symlink_path.paint("/"));
                    }
                }

                if !target.name.is_empty() {
                    bits.push(file_colour(colours, &target).paint(target.name));
                }
            },

            FileTarget::Broken(broken_path) => {
                bits.push(Style::default().paint(" "));
                bits.push(colours.broken_arrow.paint("->"));
                bits.push(Style::default().paint(" "));
                bits.push(colours.broken_filename.paint(broken_path.display().to_string()));
            },

            FileTarget::Err(_) => {
                // Do nothing -- the error gets displayed on the next line
            }
        }
    } else if classify {
        if file.is_executable_file() {
            bits.push(Style::default().paint("*"));
        } else if file.is_directory() {
            bits.push(Style::default().paint("/"));
        } else if file.is_pipe() {
            bits.push(Style::default().paint("|"));
        } else if file.is_link() {
            bits.push(Style::default().paint("@"));
        } else if file.is_socket() {
            bits.push(Style::default().paint("="));
        }
    }

    bits.into()
}

pub fn file_colour(colours: &Colours, file: &File) -> Style {
    match file {
        f if f.is_directory()        => colours.filetypes.directory,
        f if f.is_executable_file()  => colours.filetypes.executable,
        f if f.is_link()             => colours.filetypes.symlink,
        f if f.is_pipe()             => colours.filetypes.pipe,
        f if f.is_char_device()
           | f.is_block_device()     => colours.filetypes.device,
        f if f.is_socket()           => colours.filetypes.socket,
        f if !f.is_file()            => colours.filetypes.special,
        f if f.is_immediate()        => colours.filetypes.immediate,
        f if f.is_image()            => colours.filetypes.image,
        f if f.is_video()            => colours.filetypes.video,
        f if f.is_music()            => colours.filetypes.music,
        f if f.is_lossless()         => colours.filetypes.lossless,
        f if f.is_crypto()           => colours.filetypes.crypto,
        f if f.is_document()         => colours.filetypes.document,
        f if f.is_compressed()       => colours.filetypes.compressed,
        f if f.is_temp()             => colours.filetypes.temp,
        f if f.is_compiled()         => colours.filetypes.compiled,
        _                            => colours.filetypes.normal,
    }
}
<|endoftext|>


<commit_before>//! # Command Parser
//!
//! The ``commands::parser`` module provides:
//!
//! * Functionality for building a tree of commands based on their names.
//! * Parsing tokenized input to select a command. Input tokenization can
//!   be performed by the ``commands::tokenizer`` module.
//! * Validating parameters.
//! * Performing completion on commands and parameters.
//!
//! The parser is still a work in progress but is rapidly advancing.

pub mod nodes;
pub mod completion;

use std::collections::HashMap;
use std::rc::Rc;
use parser::nodes::*;
use tokenizer::{Token, TokenType};
use parser::completion::{Complete, Completion};

/// Command parser
///
/// The lifetime parameter `'p` refers to the lifetime of the
/// root node of the command tree that was used to create this
/// parser.
///
/// The lifetime parameter `'p` refers to the lifetime of the parser
/// and of the tokens passed into this parser.
pub struct Parser<'p> {
    current_node: &'p Rc<Node>,
    /// The nodes which have been accepted during `parse` or `advance`.
    pub nodes: Vec<&'p Rc<Node>>,
    /// The tokens which have been accepted during `parse` or `advance`.
    pub tokens: Vec<&'p Token<'p>>,
    commands: Vec<&'p Rc<CommandNode>>,
    parameters: HashMap<String, String>,
}

impl<'p> Parser<'p> {
    /// Construct a parser with a root node.
    pub fn new(initial_node: &'p Rc<Node>) -> Parser<'p> {
        Parser {
            current_node: initial_node,
            nodes: vec![],
            tokens: vec![],
            commands: vec![],
            parameters: HashMap::new(),
        }
    }

    /// Given an optional token, get the possible valid completions
    /// for the current parser state.
    pub fn complete(&self, token: Option<&'p Token<'p>>) -> Vec<Completion> {
        fn possible_completion(node: &Rc<Node>, parser: &Parser, token: Option<&Token>) -> bool {
            // To be a possible completion, the node should not be
            // hidden, it should be acceptable, and if there's a token,
            // it should be a valid match for the node.
            !node.hidden() && node.acceptable(parser) &&
            match token {
                Some(t) => node.matches(parser, t),
                _ => true,
            }
        }
        self.current_node
            .successors()
            .into_iter()
            .filter(|n| possible_completion(n, self, token))
            .map(|n| n.complete(token))
            .collect::<Vec<_>>()
    }

    /// Parse a vector of tokens, advancing through the
    /// node hierarchy.
    pub fn parse(&mut self, tokens: Vec<&'p Token<'p>>) {
        for token in tokens {
            if token.token_type != TokenType::Whitespace {
                self.advance(token);
            }
        }
    }

    /// Parse a single token, advancing through the node hierarchy.
    pub fn advance(&mut self, token: &'p Token<'p>) {
        let matches = self.current_node
                          .successors()
                          .into_iter()
                          .filter(|n| n.acceptable(self) && n.matches(self, token))
                          .collect::<Vec<_>>();
        match matches.len() {
            1 => {
                let matching_node = &matches[0];
                matching_node.accept(self, token);
                self.current_node = matching_node.clone();
                self.nodes.push(matching_node);
                self.tokens.push(token);
            }
            0 => panic!("No matches for '{}'.", token.text),
            _ => panic!("Ambiguous matches for '{}'.", token.text),
        }
    }

    /// Execute the command that has been accepted by the parser.
    ///
    /// * XXX: This isn't implemented yet.
    /// * XXX: This should be returning a Result probably.
    pub fn execute(&self) {
        if !self.commands.is_empty() {
            // self.commands[0].execute(self)
        }
    }

    /// Verify that the parser is in a valid state with
    /// respect to having accepted a command and all
    /// required parameters.
    ///
    /// * XXX: This isn't implemented yet.
    /// * XXX: This should be returning Option or Result
    ///        with an enum for the various error conditions.
    pub fn verify(&self) -> bool {
        if self.commands.is_empty() {
            // XXX: We'll want an enum error here with a Result.
            return false;
        } else {
            for expected in self.commands[0].parameters() {
                if expected.required() {
                    if !self.parameters.contains_key(expected.name()) {
                        return false;
                    }
                }
            }
        }
        true
    }
}

trait Advance {
    fn acceptable(&self, parser: &Parser) -> bool;

    fn matches(&self, parser: &Parser, token: &Token) -> bool;
}

impl Advance for Node {
    fn acceptable(&self, _parser: &Parser) -> bool {
        unimplemented!();
        // !parser.nodes.contains(self)
    }

    fn matches(&self, _parser: &Parser, token: &Token) -> bool {
        self.name().starts_with(token.text)
    }
}

trait Accept {
    fn accept<'p>(&'p self, parser: &mut Parser<'p>, token: &Token);
}

impl Accept for Node {
    fn accept<'p>(&'p self, _parser: &mut Parser<'p>, _token: &Token) {}
}

impl Accept for Rc<CommandNode> {
    fn accept<'p>(&'p self, parser: &mut Parser<'p>, _token: &Token) {
        match self.handler() {
            Some(_) => parser.commands.push(self),
            _ => {}
        }
    }
}

impl Accept for Rc<ParameterNode> {
    fn accept<'p>(&'p self, parser: &mut Parser<'p>, token: &Token) {
        if self.repeatable() {
            unimplemented!();
        } else {
            parser.parameters.insert(self.name().clone(), token.text.to_string());
        }
    }
}
<commit_msg>parser: Use match on tokenType rather than if.<commit_after>//! # Command Parser
//!
//! The ``commands::parser`` module provides:
//!
//! * Functionality for building a tree of commands based on their names.
//! * Parsing tokenized input to select a command. Input tokenization can
//!   be performed by the ``commands::tokenizer`` module.
//! * Validating parameters.
//! * Performing completion on commands and parameters.
//!
//! The parser is still a work in progress but is rapidly advancing.

pub mod nodes;
pub mod completion;

use std::collections::HashMap;
use std::rc::Rc;
use parser::nodes::*;
use tokenizer::{Token, TokenType};
use parser::completion::{Complete, Completion};

/// Command parser
///
/// The lifetime parameter `'p` refers to the lifetime of the
/// root node of the command tree that was used to create this
/// parser.
///
/// The lifetime parameter `'p` refers to the lifetime of the parser
/// and of the tokens passed into this parser.
pub struct Parser<'p> {
    current_node: &'p Rc<Node>,
    /// The nodes which have been accepted during `parse` or `advance`.
    pub nodes: Vec<&'p Rc<Node>>,
    /// The tokens which have been accepted during `parse` or `advance`.
    pub tokens: Vec<&'p Token<'p>>,
    commands: Vec<&'p Rc<CommandNode>>,
    parameters: HashMap<String, String>,
}

impl<'p> Parser<'p> {
    /// Construct a parser with a root node.
    pub fn new(initial_node: &'p Rc<Node>) -> Parser<'p> {
        Parser {
            current_node: initial_node,
            nodes: vec![],
            tokens: vec![],
            commands: vec![],
            parameters: HashMap::new(),
        }
    }

    /// Given an optional token, get the possible valid completions
    /// for the current parser state.
    pub fn complete(&self, token: Option<&'p Token<'p>>) -> Vec<Completion> {
        fn possible_completion(node: &Rc<Node>, parser: &Parser, token: Option<&Token>) -> bool {
            // To be a possible completion, the node should not be
            // hidden, it should be acceptable, and if there's a token,
            // it should be a valid match for the node.
            !node.hidden() && node.acceptable(parser) &&
            match token {
                Some(t) => node.matches(parser, t),
                _ => true,
            }
        }
        self.current_node
            .successors()
            .into_iter()
            .filter(|n| possible_completion(n, self, token))
            .map(|n| n.complete(token))
            .collect::<Vec<_>>()
    }

    /// Parse a vector of tokens, advancing through the
    /// node hierarchy.
    pub fn parse(&mut self, tokens: Vec<&'p Token<'p>>) {
        for token in tokens {
            match token.token_type {
                TokenType::Invalid => unreachable!(),
                TokenType::Whitespace => {}
                TokenType::Word => self.advance(token),
            }
        }
    }

    /// Parse a single token, advancing through the node hierarchy.
    pub fn advance(&mut self, token: &'p Token<'p>) {
        let matches = self.current_node
                          .successors()
                          .into_iter()
                          .filter(|n| n.acceptable(self) && n.matches(self, token))
                          .collect::<Vec<_>>();
        match matches.len() {
            1 => {
                let matching_node = &matches[0];
                matching_node.accept(self, token);
                self.current_node = matching_node.clone();
                self.nodes.push(matching_node);
                self.tokens.push(token);
            }
            0 => panic!("No matches for '{}'.", token.text),
            _ => panic!("Ambiguous matches for '{}'.", token.text),
        }
    }

    /// Execute the command that has been accepted by the parser.
    ///
    /// * XXX: This isn't implemented yet.
    /// * XXX: This should be returning a Result probably.
    pub fn execute(&self) {
        if !self.commands.is_empty() {
            // self.commands[0].execute(self)
        }
    }

    /// Verify that the parser is in a valid state with
    /// respect to having accepted a command and all
    /// required parameters.
    ///
    /// * XXX: This isn't implemented yet.
    /// * XXX: This should be returning Option or Result
    ///        with an enum for the various error conditions.
    pub fn verify(&self) -> bool {
        if self.commands.is_empty() {
            // XXX: We'll want an enum error here with a Result.
            return false;
        } else {
            for expected in self.commands[0].parameters() {
                if expected.required() {
                    if !self.parameters.contains_key(expected.name()) {
                        return false;
                    }
                }
            }
        }
        true
    }
}

trait Advance {
    fn acceptable(&self, parser: &Parser) -> bool;

    fn matches(&self, parser: &Parser, token: &Token) -> bool;
}

impl Advance for Node {
    fn acceptable(&self, _parser: &Parser) -> bool {
        unimplemented!();
        // !parser.nodes.contains(self)
    }

    fn matches(&self, _parser: &Parser, token: &Token) -> bool {
        self.name().starts_with(token.text)
    }
}

trait Accept {
    fn accept<'p>(&'p self, parser: &mut Parser<'p>, token: &Token);
}

impl Accept for Node {
    fn accept<'p>(&'p self, _parser: &mut Parser<'p>, _token: &Token) {}
}

impl Accept for Rc<CommandNode> {
    fn accept<'p>(&'p self, parser: &mut Parser<'p>, _token: &Token) {
        match self.handler() {
            Some(_) => parser.commands.push(self),
            _ => {}
        }
    }
}

impl Accept for Rc<ParameterNode> {
    fn accept<'p>(&'p self, parser: &mut Parser<'p>, token: &Token) {
        if self.repeatable() {
            unimplemented!();
        } else {
            parser.parameters.insert(self.name().clone(), token.text.to_string());
        }
    }
}
<|endoftext|>