<commit_before>pub mod space;
pub mod seq;
pub mod seq_of;
pub mod set;
pub mod set_of;
pub mod choice;
pub mod int;
pub mod spec;

use nom::{is_alphanumeric, alpha, digit};

use parse::space::skip_other;
use parse::seq::asn1_seq;
use parse::seq_of::asn1_seq_of;
use parse::set::asn1_set;
use parse::set_of::asn1_set_of;
use parse::choice::asn1_choice;
use parse::int::asn1_integer;
use data::{Asn1Type, Asn1Class, Asn1Tag, Asn1Def, Asn1Field, Asn1FieldDef,
           Asn1Optional};

named!(pub asn1_class_tag <Asn1Tag>, do_parse!(
  class: opt!(alpha) >>
  opt!(skip_other) >>
  tag_num: digit >>
  ( {
      let class = class.and_then(|i|
        String::from_utf8(Vec::from(i)).ok()
      );
      Asn1Class::parse(class).expect("Couldn't parse tag class")
    },
    String::from_utf8(Vec::from(tag_num)).unwrap().parse().expect("Couldn't parse tag number")
  )
));

named!(pub asn1_tag <Asn1Tag>, do_parse!(
  tag: delimited!(
    tag!("["),
    asn1_class_tag,
    tuple!(opt!(skip_other), tag!("]"))
  ) >>
  (tag)
));

named!(pub asn1_type_def <Asn1Def>, do_parse!(
  name: asn1_type_name >>
  opt!(skip_other) >>
  tag!("::=") >>
  opt!(skip_other) >>
  tag: opt!(asn1_tag) >>
  opt!(skip_other) >>
  asn1_type: asn1_type >>
  (Asn1Def {
    name: name,
    tag: tag,
    assign: asn1_type,
  })
));

named!(pub asn1_type <Asn1Type>, alt!(
  asn1_seq |
  asn1_seq_of |
  asn1_set |
  asn1_set_of |
  asn1_choice |
  asn1_integer |
  asn1_assignment
));

named!(pub non_empty_string, take_while1!(is_alphanumeric));

named!(pub asn1_type_name <String>, do_parse!(
  s: alt!(
    tag!("BIT STRING") |
    tag!("OCTET STRING") |
    tag!("OBJECT IDENTIFIER") |
    tag!("INSTANCE OF") |
    tag!("EMBEDDED PDV") |
    tag!("CHARACTER STRING") |
    call!(non_empty_string)
  ) >>
  (String::from_utf8(Vec::from(s)).unwrap())
));

named!(pub asn1_assignment <Asn1Type>, do_parse!(
  t: asn1_type_name >>
  (Asn1Type::Type(t))
));

named!(pub extent_marker <Asn1Field>, do_parse!(
  tag!("...") >>
  (Asn1Field::ExtentMarker)
));

named!(pub asn1_field <Asn1Field>, alt!(
  extent_marker |
  do_parse!(
    def: asn1_field_def >>
    (Asn1Field::Def(def))
  )
));

named!(pub asn1_field_def <Asn1FieldDef>, do_parse!(
  name: asn1_type_name >>
  opt!(skip_other) >>
  tag: opt!(asn1_tag) >>
  opt!(skip_other) >>
  asn1_type: asn1_type >>
  opt!(skip_other) >>
  optional: opt!(alt!(asn1_field_optional | asn1_field_default)) >>
  (Asn1FieldDef {
    name: name,
    tag: tag,
    asn1_type: asn1_type,
    optional: optional,
  })
));

named!(pub asn1_field_optional <Asn1Optional>, do_parse!(
  tag!("OPTIONAL") >>
  (Asn1Optional::Optional)
));

named!(pub asn1_field_default <Asn1Optional>, do_parse!(
  tag!("DEFAULT") >>
  opt!(skip_other) >>
  default: take_while!(is_alphanumeric) >>
  (Asn1Optional::Default(
    String::from_utf8(Vec::from(default)).unwrap()
  ))
));

#[test]
fn test_asn1_type() {
  assert_eq!(asn1_type_name("Foo Bar".as_bytes()).unwrap().1, "Foo");
  assert_eq!(asn1_type_name("OCTET STRING".as_bytes()).unwrap().1, "OCTET STRING");
}

#[test]
fn test_asn1_tag() {
  let tag: Asn1Tag = (Asn1Class::ContextSpecific, 32);
  assert_eq!(asn1_tag("[32]".as_bytes()).unwrap().1, tag);
  assert_eq!(asn1_tag("[ 32 ]".as_bytes()).unwrap().1, tag);
  assert_eq!(
    asn1_tag("[APPLICATION 12]".as_bytes()).unwrap().1,
    (Asn1Class::Application, 12)
  );
  assert_eq!(
    asn1_tag("[PRIVATE 24]".as_bytes()).unwrap().1,
    (Asn1Class::Private, 24)
  );
}

#[test]
fn test_asn1_field() {
  let field1 = ::Asn1FieldDef {
    name: "foo".into(),
    tag: None,
    asn1_type: ::Asn1Type::Type("Bar".into()),
    optional: None,
  };
  let field2 = ::Asn1FieldDef {
    name: "asdf".into(),
    tag: Some((Asn1Class::Application, 9)),
    asn1_type: ::Asn1Type::Integer,
    optional: Some(Asn1Optional::Optional),
  };
  let field3 = ::Asn1FieldDef {
    name: "sample".into(),
    tag: None,
    asn1_type: ::Asn1Type::Integer,
    optional: Some(Asn1Optional::Default("TRUE".into())),
  };
  assert_eq!(
    field1,
    asn1_field_def("foo Bar,".as_bytes()).unwrap().1
  );
  assert_eq!(
    field2,
    asn1_field_def("asdf [APPLICATION 9] INTEGER OPTIONAL,".as_bytes()).unwrap().1
  );
  assert_eq!(
    field1,
    asn1_field_def("foo--test\n Bar,".as_bytes()).unwrap().1
  );
  assert_eq!(
    field3,
    asn1_field_def("sample INTEGER DEFAULT TRUE,".as_bytes()).unwrap().1
  );
  assert_eq!(
    Asn1Field::Def(field3),
    asn1_field("sample INTEGER DEFAULT TRUE,".as_bytes()).unwrap().1
  );
  assert_eq!(
    Asn1Field::ExtentMarker,
    asn1_field("...".as_bytes()).unwrap().1
  );
}
<commit_msg>Allow dashes in type names<commit_after>pub mod space;
pub mod seq;
pub mod seq_of;
pub mod set;
pub mod set_of;
pub mod choice;
pub mod int;
pub mod spec;

use nom::{is_alphanumeric, alpha, digit};

use parse::space::skip_other;
use parse::seq::asn1_seq;
use parse::seq_of::asn1_seq_of;
use parse::set::asn1_set;
use parse::set_of::asn1_set_of;
use parse::choice::asn1_choice;
use parse::int::asn1_integer;
use data::{Asn1Type, Asn1Class, Asn1Tag, Asn1Def, Asn1Field, Asn1FieldDef,
           Asn1Optional};

named!(pub asn1_class_tag <Asn1Tag>, do_parse!(
  class: opt!(alpha) >>
  opt!(skip_other) >>
  tag_num: digit >>
  ( {
      let class = class.and_then(|i|
        String::from_utf8(Vec::from(i)).ok()
      );
      Asn1Class::parse(class).expect("Couldn't parse tag class")
    },
    String::from_utf8(Vec::from(tag_num)).unwrap().parse().expect("Couldn't parse tag number")
  )
));

named!(pub asn1_tag <Asn1Tag>, do_parse!(
  tag: delimited!(
    tag!("["),
    asn1_class_tag,
    tuple!(opt!(skip_other), tag!("]"))
  ) >>
  (tag)
));

named!(pub asn1_type_def <Asn1Def>, do_parse!(
  name: asn1_type_name >>
  opt!(skip_other) >>
  tag!("::=") >>
  opt!(skip_other) >>
  tag: opt!(asn1_tag) >>
  opt!(skip_other) >>
  asn1_type: asn1_type >>
  (Asn1Def {
    name: name,
    tag: tag,
    assign: asn1_type,
  })
));

named!(pub asn1_type <Asn1Type>, alt!(
  asn1_seq |
  asn1_seq_of |
  asn1_set |
  asn1_set_of |
  asn1_choice |
  asn1_integer |
  asn1_assignment
));

pub fn is_asn1_type_char(chr: u8) -> bool {
  is_alphanumeric(chr) || chr == '-' as u8
}

named!(pub asn1_type_name <String>, do_parse!(
  s: alt!(
    tag!("BIT STRING") |
    tag!("OCTET STRING") |
    tag!("OBJECT IDENTIFIER") |
    tag!("INSTANCE OF") |
    tag!("EMBEDDED PDV") |
    tag!("CHARACTER STRING") |
    take_while1!(is_asn1_type_char)
  ) >>
  (String::from_utf8(Vec::from(s)).unwrap())
));

named!(pub asn1_assignment <Asn1Type>, do_parse!(
  t: asn1_type_name >>
  (Asn1Type::Type(t))
));

named!(pub extent_marker <Asn1Field>, do_parse!(
  tag!("...") >>
  (Asn1Field::ExtentMarker)
));

named!(pub asn1_field <Asn1Field>, alt!(
  extent_marker |
  do_parse!(
    def: asn1_field_def >>
    (Asn1Field::Def(def))
  )
));

named!(pub asn1_field_def <Asn1FieldDef>, do_parse!(
  name: asn1_type_name >>
  opt!(skip_other) >>
  tag: opt!(asn1_tag) >>
  opt!(skip_other) >>
  asn1_type: asn1_type >>
  opt!(skip_other) >>
  optional: opt!(alt!(asn1_field_optional | asn1_field_default)) >>
  (Asn1FieldDef {
    name: name,
    tag: tag,
    asn1_type: asn1_type,
    optional: optional,
  })
));

named!(pub asn1_field_optional <Asn1Optional>, do_parse!(
  tag!("OPTIONAL") >>
  (Asn1Optional::Optional)
));

named!(pub asn1_field_default <Asn1Optional>, do_parse!(
  tag!("DEFAULT") >>
  opt!(skip_other) >>
  default: take_while!(is_alphanumeric) >>
  (Asn1Optional::Default(
    String::from_utf8(Vec::from(default)).unwrap()
  ))
));

#[test]
fn test_asn1_type() {
  assert_eq!(asn1_type_name("Foo Bar".as_bytes()).unwrap().1, "Foo");
  assert_eq!(asn1_type_name("OCTET STRING".as_bytes()).unwrap().1, "OCTET STRING");
}

#[test]
fn test_asn1_tag() {
  let tag: Asn1Tag = (Asn1Class::ContextSpecific, 32);
  assert_eq!(asn1_tag("[32]".as_bytes()).unwrap().1, tag);
  assert_eq!(asn1_tag("[ 32 ]".as_bytes()).unwrap().1, tag);
  assert_eq!(
    asn1_tag("[APPLICATION 12]".as_bytes()).unwrap().1,
    (Asn1Class::Application, 12)
  );
  assert_eq!(
    asn1_tag("[PRIVATE 24]".as_bytes()).unwrap().1,
    (Asn1Class::Private, 24)
  );
}

#[test]
fn test_asn1_field() {
  let field1 = ::Asn1FieldDef {
    name: "foo".into(),
    tag: None,
    asn1_type: ::Asn1Type::Type("Bar".into()),
    optional: None,
  };
  let field2 = ::Asn1FieldDef {
    name: "asdf".into(),
    tag: Some((Asn1Class::Application, 9)),
    asn1_type: ::Asn1Type::Integer,
    optional: Some(Asn1Optional::Optional),
  };
  let field3 = ::Asn1FieldDef {
    name: "sample".into(),
    tag: None,
    asn1_type: ::Asn1Type::Integer,
    optional: Some(Asn1Optional::Default("TRUE".into())),
  };
  assert_eq!(
    field1,
    asn1_field_def("foo Bar,".as_bytes()).unwrap().1
  );
  assert_eq!(
    field2,
    asn1_field_def("asdf [APPLICATION 9] INTEGER OPTIONAL,".as_bytes()).unwrap().1
  );
  assert_eq!(
    field1,
    asn1_field_def("foo --test\n Bar,".as_bytes()).unwrap().1
  );
  assert_eq!(
    field3,
    asn1_field_def("sample INTEGER DEFAULT TRUE,".as_bytes()).unwrap().1
  );
  assert_eq!(
    Asn1Field::Def(field3),
    asn1_field("sample INTEGER DEFAULT TRUE,".as_bytes()).unwrap().1
  );
  assert_eq!(
    Asn1Field::ExtentMarker,
    asn1_field("...".as_bytes()).unwrap().1
  );
}
<|endoftext|>


<commit_before>/* diosix debug console output code
 *
 * (c) Chris Williams, 2019-2021.
 *
 * See LICENSE for usage and copying.
 */

/* to avoid warnings about super::hardware when qemuprint is active */
#![allow(unused_imports)]

use super::error::Cause;
use core::fmt;
use super::lock::Mutex;
use alloc::vec::Vec;
use alloc::string::String;
use super::hardware;
use super::service;
use super::message;

/* here's the logic for the hypervisor's debug queues
    * all the hvprint macros feed into DEBUG_QUEUE
    * the hypervisor will select a physical CPU core in between workloads to drain DEBUG_QUEUE
    * DEBUG_QUEUE will be drained into two channels: DEBUG_LOG, and the system debug output port
      (typically a serial port) if a user interface capsule isn't running
    * the user interface capsule will drain DEBUG_LOG
    * DEBUG_LOG will have a fixed limit to avoid it chewing up too much RAM
    * if the qemuprint feature is active, the system debug output port will always be the
      Qemu virt serial port regardless of what's in the host hardware's device tree
*/

const DEBUG_LOG_MAX_LEN: usize = 64 * 1024; /* 64KB max length for debug log buffer */

lazy_static!
{
    pub static ref DEBUG_LOCK: Mutex<bool> = Mutex::new("primary debug lock", false);
    static ref DEBUG_QUEUE: Mutex<String> = Mutex::new("debug output queue", String::new());
    static ref DEBUG_LOG: Mutex<Vec<char>> = Mutex::new("debug log buffer", Vec::new());
}

/* top level debug macros */
/* useful messages */
#[macro_export]
macro_rules! hvlog
{
    ($fmt:expr) => (hvprintln!("[+] CPU {}: {}", $crate::pcore::PhysicalCore::get_id(), $fmt));
    ($fmt:expr, $($arg:tt)*) => (hvprintln!(concat!("[+] CPU {}: ", $fmt), $crate::pcore::PhysicalCore::get_id(), $($arg)*));
}

/* bad news: bug detection, failures, etc. */
#[macro_export]
macro_rules! hvalert
{
    ($fmt:expr) => (hvprintln!("[!] CPU {}: {}", $crate::pcore::PhysicalCore::get_id(), $fmt));
    ($fmt:expr, $($arg:tt)*) => (hvprintln!(concat!("[!] CPU {}: ", $fmt), $crate::pcore::PhysicalCore::get_id(), $($arg)*));
}

/* only output if debug build is enabled */
#[macro_export]
#[cfg(debug_assertions)]
macro_rules! hvdebug
{
    ($fmt:expr) => (hvprintln!("[?] CPU {}: {}", $crate::pcore::PhysicalCore::get_id(), $fmt));
    ($fmt:expr, $($arg:tt)*) => (hvprintln!(concat!("[?] CPU {}: ", $fmt), $crate::pcore::PhysicalCore::get_id(), $($arg)*));
}

/* silence debug if disabled */
#[macro_export]
#[cfg(not(debug_assertions))]
macro_rules! hvdebug
{
    ($fmt:expr) => ({});
    ($fmt:expr, $($arg:tt)*) => ({});
}

/* don't include any metadata nor add a newline */
#[macro_export]
#[cfg(debug_assertions)]
macro_rules! hvdebugraw
{
    ($fmt:expr) => (hvprint!("{}", $fmt));
    ($fmt:expr, $($arg:tt)*) => (hvprint!(concat!($fmt), $($arg)*));
}

/* silence debug if disabled */
#[macro_export]
#[cfg(not(debug_assertions))]
macro_rules! hvdebugraw
{
    ($fmt:expr) => ({});
    ($fmt:expr, $($arg:tt)*) => ({});
}

/* low-level macros for hypervisor-only hvprintln and hvprint debug output routines */
macro_rules! hvprintln
{
    ($fmt:expr) => (hvprint!(concat!($fmt, "\n")));
    ($fmt:expr, $($arg:tt)*) => (hvprint!(concat!($fmt, "\n"), $($arg)*));
}

macro_rules! hvprint
{
    ($($arg:tt)*) =>
    ({
        use core::fmt::Write;
        {
            let mut hvprint_lock = $crate::debug::DEBUG_LOCK.lock();
            *hvprint_lock = true;

            unsafe { $crate::debug::CONSOLE.write_fmt(format_args!($($arg)*)).unwrap(); }
        }
    });
}

macro_rules! debughousekeeper
{
    () => ($crate::debug::drain_queue());
}

/* create a generic debug console writer */
pub struct ConsoleWriter;
pub static mut CONSOLE: ConsoleWriter = ConsoleWriter {};

impl fmt::Write for ConsoleWriter
{
    fn write_str(&mut self, s: &str) -> core::fmt::Result
    {
        DEBUG_QUEUE.lock().push_str(s);
        Ok(())
    }
}

/* drain the debug queue into the debug logging buffer, and if no user interface
   is available yet, drain the queue into the system debug output port */
pub fn drain_queue()
{
    /* avoid blocking if we can't write at this time */
    if DEBUG_LOCK.is_locked() == false
    {
        let mut debug_lock = DEBUG_LOCK.lock();
        *debug_lock = true;
        let mut debug_queue = DEBUG_QUEUE.lock();
        let mut debug_log = DEBUG_LOG.lock();

        /* copy the debug queue out to the system debug output port ourselves if there's
           no user interface yet */
        if service::is_registered(service::ServiceType::ConsoleInterface) == false
        {
            if cfg!(feature = "qemuprint")
            {
                /* force debug output to Qemu's serial port. useful for early debugging */
                for c in debug_queue.as_bytes()
                {
                    /* this is the serial port address in qemu's RISC-V virt emulation */
                    if cfg!(target_arch = "riscv64") || cfg!(target_arch = "riscv32")
                    {
                        unsafe { *(0x10000000 as *mut u8) = *c };
                    }
                }
            }
            else
            {
                /* write out the debug info to the registered output interface.
                   bail out now if this failed */
                if hardware::write_debug_string(&debug_queue) == false
                {
                    return;
                }
            }
        }

        /* drain the debug queue to the log buffer so it can be fetched later by the
           user interface service */
        for c in debug_queue.as_str().chars()
        {
            debug_log.push(c);
        }
        debug_queue.clear();

        /* truncate the log buffer if it's too long */
        if debug_log.len() > DEBUG_LOG_MAX_LEN
        {
            let to_truncate = debug_log.len() - DEBUG_LOG_MAX_LEN;
            debug_log.drain(0..to_truncate);
        }
    }
}

/* pick off the next character in the hypervisor log output buffer,
   or None if the buffer is empty */
pub fn get_log_char() -> Option<char>
{
    let mut debug_log = DEBUG_LOG.lock();
    if debug_log.len() > 0
    {
        return Some(debug_log.remove(0));
    }
    None
}<commit_msg>Remove support for RV32<commit_after>/* diosix debug console output code
 *
 * (c) Chris Williams, 2019-2021.
 *
 * See LICENSE for usage and copying.
 */

/* to avoid warnings about super::hardware when qemuprint is active */
#![allow(unused_imports)]

use super::error::Cause;
use core::fmt;
use super::lock::Mutex;
use alloc::vec::Vec;
use alloc::string::String;
use super::hardware;
use super::service;
use super::message;

/* here's the logic for the hypervisor's debug queues
    * all the hvprint macros feed into DEBUG_QUEUE
    * the hypervisor will select a physical CPU core in between workloads to drain DEBUG_QUEUE
    * DEBUG_QUEUE will be drained into two channels: DEBUG_LOG, and the system debug output port
      (typically a serial port) if a user interface capsule isn't running
    * the user interface capsule will drain DEBUG_LOG
    * DEBUG_LOG will have a fixed limit to avoid it chewing up too much RAM
    * if the qemuprint feature is active, the system debug output port will always be the
      Qemu virt serial port regardless of what's in the host hardware's device tree
*/

const DEBUG_LOG_MAX_LEN: usize = 64 * 1024; /* 64KB max length for debug log buffer */

lazy_static!
{
    pub static ref DEBUG_LOCK: Mutex<bool> = Mutex::new("primary debug lock", false);
    static ref DEBUG_QUEUE: Mutex<String> = Mutex::new("debug output queue", String::new());
    static ref DEBUG_LOG: Mutex<Vec<char>> = Mutex::new("debug log buffer", Vec::new());
}

/* top level debug macros */
/* useful messages */
#[macro_export]
macro_rules! hvlog
{
    ($fmt:expr) => (hvprintln!("[+] CPU {}: {}", $crate::pcore::PhysicalCore::get_id(), $fmt));
    ($fmt:expr, $($arg:tt)*) => (hvprintln!(concat!("[+] CPU {}: ", $fmt), $crate::pcore::PhysicalCore::get_id(), $($arg)*));
}

/* bad news: bug detection, failures, etc. */
#[macro_export]
macro_rules! hvalert
{
    ($fmt:expr) => (hvprintln!("[!] CPU {}: {}", $crate::pcore::PhysicalCore::get_id(), $fmt));
    ($fmt:expr, $($arg:tt)*) => (hvprintln!(concat!("[!] CPU {}: ", $fmt), $crate::pcore::PhysicalCore::get_id(), $($arg)*));
}

/* only output if debug build is enabled */
#[macro_export]
#[cfg(debug_assertions)]
macro_rules! hvdebug
{
    ($fmt:expr) => (hvprintln!("[?] CPU {}: {}", $crate::pcore::PhysicalCore::get_id(), $fmt));
    ($fmt:expr, $($arg:tt)*) => (hvprintln!(concat!("[?] CPU {}: ", $fmt), $crate::pcore::PhysicalCore::get_id(), $($arg)*));
}

/* silence debug if disabled */
#[macro_export]
#[cfg(not(debug_assertions))]
macro_rules! hvdebug
{
    ($fmt:expr) => ({});
    ($fmt:expr, $($arg:tt)*) => ({});
}

/* don't include any metadata nor add a newline */
#[macro_export]
#[cfg(debug_assertions)]
macro_rules! hvdebugraw
{
    ($fmt:expr) => (hvprint!("{}", $fmt));
    ($fmt:expr, $($arg:tt)*) => (hvprint!(concat!($fmt), $($arg)*));
}

/* silence debug if disabled */
#[macro_export]
#[cfg(not(debug_assertions))]
macro_rules! hvdebugraw
{
    ($fmt:expr) => ({});
    ($fmt:expr, $($arg:tt)*) => ({});
}

/* low-level macros for hypervisor-only hvprintln and hvprint debug output routines */
macro_rules! hvprintln
{
    ($fmt:expr) => (hvprint!(concat!($fmt, "\n")));
    ($fmt:expr, $($arg:tt)*) => (hvprint!(concat!($fmt, "\n"), $($arg)*));
}

macro_rules! hvprint
{
    ($($arg:tt)*) =>
    ({
        use core::fmt::Write;
        {
            let mut hvprint_lock = $crate::debug::DEBUG_LOCK.lock();
            *hvprint_lock = true;

            unsafe { $crate::debug::CONSOLE.write_fmt(format_args!($($arg)*)).unwrap(); }
        }
    });
}

macro_rules! debughousekeeper
{
    () => ($crate::debug::drain_queue());
}

/* create a generic debug console writer */
pub struct ConsoleWriter;
pub static mut CONSOLE: ConsoleWriter = ConsoleWriter {};

impl fmt::Write for ConsoleWriter
{
    fn write_str(&mut self, s: &str) -> core::fmt::Result
    {
        DEBUG_QUEUE.lock().push_str(s);
        Ok(())
    }
}

/* drain the debug queue into the debug logging buffer, and if no user interface
   is available yet, drain the queue into the system debug output port */
pub fn drain_queue()
{
    /* avoid blocking if we can't write at this time */
    if DEBUG_LOCK.is_locked() == false
    {
        let mut debug_lock = DEBUG_LOCK.lock();
        *debug_lock = true;
        let mut debug_queue = DEBUG_QUEUE.lock();
        let mut debug_log = DEBUG_LOG.lock();

        /* copy the debug queue out to the system debug output port ourselves if there's
           no user interface yet */
        if service::is_registered(service::ServiceType::ConsoleInterface) == false
        {
            if cfg!(feature = "qemuprint")
            {
                /* force debug output to Qemu's serial port. useful for early debugging */
                for c in debug_queue.as_bytes()
                {
                    /* this is the serial port address in qemu's RISC-V virt emulation */
                    if cfg!(target_arch = "riscv64")
                    {
                        unsafe { *(0x10000000 as *mut u8) = *c };
                    }
                }
            }
            else
            {
                /* write out the debug info to the registered output interface.
                   bail out now if this failed */
                if hardware::write_debug_string(&debug_queue) == false
                {
                    return;
                }
            }
        }

        /* drain the debug queue to the log buffer so it can be fetched later by the
           user interface service */
        for c in debug_queue.as_str().chars()
        {
            debug_log.push(c);
        }
        debug_queue.clear();

        /* truncate the log buffer if it's too long */
        if debug_log.len() > DEBUG_LOG_MAX_LEN
        {
            let to_truncate = debug_log.len() - DEBUG_LOG_MAX_LEN;
            debug_log.drain(0..to_truncate);
        }
    }
}

/* pick off the next character in the hypervisor log output buffer,
   or None if the buffer is empty */
pub fn get_log_char() -> Option<char>
{
    let mut debug_log = DEBUG_LOG.lock();
    if debug_log.len() > 0
    {
        return Some(debug_log.remove(0));
    }
    None
}<|endoftext|>


<commit_before>
use clap::{SubCommand, App, Arg, ArgMatches};

use std::path::Path;
use std::marker::PhantomData;
use std::collections::BTreeMap;
use std::net::SocketAddr;

use config::ConfigFile;
use blockchain::{ConsensusConfig, GenesisConfig};
use node::NodeConfig;
use storage::Storage;
use crypto::{self, PublicKey, SecretKey};

const DEFAULT_EXONUM_LISTEN_PORT: u16 = 6333;

#[derive(Debug)]
pub struct RunCommand<'a, 'b>
    where 'a: 'b
{
    _p: PhantomData<App<'a, 'b>>,
}

impl<'a, 'b> RunCommand<'a, 'b>
    where 'a: 'b
{
    pub fn new() -> App<'a, 'b> {
        SubCommand::with_name("run")
            .about("Run node with given configuration")
            .arg(Arg::with_name("NODE_CONFIG_PATH")
                     .short("c")
                     .long("node-config")
                     .value_name("NODE_CONFIG_PATH")
                     .help("Path to node configuration file")
                     .required(true)
                     .takes_value(true))
            .arg(Arg::with_name("LEVELDB_PATH")
                     .short("d")
                     .long("leveldb-path")
                     .value_name("LEVELDB_PATH")
                     .help("Use leveldb database with the given path")
                     .required(false)
                     .takes_value(true))
            .arg(Arg::with_name("PUBLIC_API_ADDRESS")
                     .long("public-api-address")
                     .help("Listen address for public api")
                     .required(false)
                     .takes_value(true))
            .arg(Arg::with_name("PRIVATE_API_ADDRESS")
                     .long("private-api-address")
                     .help("Listen address for private api")
                     .required(false)
                     .takes_value(true))
    }

    pub fn node_config_path(matches: &'a ArgMatches<'a>) -> &'a Path {
        matches
            .value_of("NODE_CONFIG_PATH")
            .map(Path::new)
            .expect("Path to node configuration is no setted")
    }

    pub fn node_config(matches: &'a ArgMatches<'a>) -> NodeConfig {
        let path = Self::node_config_path(matches);
        let mut cfg: NodeConfig = ConfigFile::load(path).unwrap();
        // Override api options
        if let Some(addr) = Self::public_api_address(matches) {
            cfg.api.public_api_address = Some(addr);
        }
        if let Some(addr) = Self::private_api_address(matches) {
            cfg.api.private_api_address = Some(addr);
        }
        cfg
    }

    pub fn public_api_address(matches: &'a ArgMatches<'a>) -> Option<SocketAddr> {
        matches
            .value_of("PUBLIC_API_ADDRESS")
            .map(|s| s.parse().expect("Public api address has incorrect format"))
    }

    pub fn private_api_address(matches: &'a ArgMatches<'a>) -> Option<SocketAddr> {
        matches
            .value_of("PRIVATE_API_ADDRESS")
            .map(|s| s.parse().expect("Private api address has incorrect format"))
    }

    pub fn leveldb_path(matches: &'a ArgMatches<'a>) -> Option<&'a Path> {
        matches.value_of("LEVELDB_PATH").map(Path::new)
    }

    #[cfg(not(feature="memorydb"))]
    pub fn db(matches: &'a ArgMatches<'a>) -> Box<Database> {
        use storage::{LevelDB, LevelDBOptions};

        let path = Self::leveldb_path(matches).unwrap();
        let mut options = LevelDBOptions::new();
        options.create_if_missing = true;
        Box::new(LevelDB::open(path, options).unwrap())
    }

    #[cfg(feature="memorydb")]
    pub fn db(_: &'a ArgMatches<'a>) -> Box<Database> {
        use storage::MemoryDB;
        Box::new(MemoryDB::new())
    }
}

#[derive(Serialize, Deserialize)]
pub struct ValidatorIdent {
    addr: SocketAddr,
}

#[derive(Serialize, Deserialize, Default)]
pub struct TemplateConfig {
    validators: BTreeMap<PublicKey, ValidatorIdent>,
    consensus_cfg: ConsensusConfig,
    count: usize
}

#[derive(Serialize, Deserialize)]
pub struct KeyConfig {
    public_key: PublicKey,
    secret_key: SecretKey,
}

pub struct KeyGeneratorCommand;
impl KeyGeneratorCommand
{
    /// Create basic keygen subcommand.
    pub fn new<'a>() -> App<'a, 'a> {
        SubCommand::with_name("keygen")
            .about("Generate basic node secret key.")
            .arg(Arg::with_name("KEYCHAIN")
                     .help("Path to key config.")
                     .required(true)
                     .index(1))
    }

    /// Path where keychain config should be saved
    pub fn keychain<'a>(matches: &'a ArgMatches<'a>) -> &'a Path {
        Path::new(matches.value_of("KEYCHAIN").unwrap())
    }

    /// Generate and write key config to `keychain()` path.
    pub fn execute_default(matches: &ArgMatches) {
        let (pub_key, sec_key) = crypto::gen_keypair();
        let config = KeyConfig {
            public_key: pub_key,
            secret_key: sec_key,
        };

        ConfigFile::save(&config, Self::keychain(matches)).unwrap();
    }
}

/// implement command for template generating
pub struct GenerateTemplateCommand;
impl GenerateTemplateCommand
{
    pub fn new<'a>() -> App<'a, 'a> {
        SubCommand::with_name("generate-template")
            .about("Generate basic template.")
            .arg(Arg::with_name("COUNT")
                     .help("Validator total count.")
                     .required(true)
                     .index(1))
            .arg(Arg::with_name("TEMPLATE")
                     .help("Path to template config.")
                     .required(true)
                     .index(2))
    }

    /// Path where template config should be saved
    pub fn template<'a>(matches: &'a ArgMatches<'a>) -> &'a Path {
        Path::new(matches.value_of("TEMPLATE").unwrap())
    }
    /// Validator total count
    pub fn count(matches: &ArgMatches) -> usize {
        matches.value_of("COUNT").unwrap().parse().unwrap()
    }

    /// Write default template config into `template()` path.
    pub fn execute_default(matches: &ArgMatches) {
        let mut template = TemplateConfig::default();
        template.count = Self::count(matches);
        ConfigFile::save(&template, Self::template(matches)).unwrap();
    }
}

pub struct PreInitCommand;
impl PreInitCommand
{
    pub fn new<'a>() -> App<'a, 'a> {
        SubCommand::with_name("preinit")
            .about("Preinit configuration, optionaly generate public and secret key.")
            .arg(Arg::with_name("TEMPLATE")
                     .help("Path to template")
                     .required(true)
                     .index(1))
            .arg(Arg::with_name("KEYCHAIN")
                     .help("Path to secret and public key file.")
                     .required(true)
                     .index(2))
             .arg(Arg::with_name("LISTEN_ADDR")
                     .short("a")
                     .long("listen-addr")
                     .value_name("LISTEN_ADDR")
                     .required(true)
                     .takes_value(true))
            .arg(Arg::with_name("PORT")
                     .short("p")
                     .long("port")
                     .value_name("PORT")
                     .required(false)
                     .takes_value(true))

    }

    pub fn keychain<'a>(matches: &'a ArgMatches<'a>) -> &'a Path {
        Path::new(matches.value_of("KEYCHAIN").unwrap())
    }

    pub fn template<'a>(matches: &'a ArgMatches<'a>) -> &'a Path {
        Path::new(matches.value_of("TEMPLATE").unwrap())
    }

    pub fn port(matches: &ArgMatches) -> Option<u16> {
        matches.value_of("PORT").and_then(|port| port.parse().ok())
    }

    pub fn addr(matches: &ArgMatches) -> String {
        matches.value_of("LISTEN_ADDR").unwrap().to_string()
    }

    #[cfg_attr(feature="cargo-clippy", allow(map_entry))]
    pub fn execute_default(matches: &ArgMatches) {
        let template_path = Self::template(matches);
        let keychain_path = Self::keychain(matches);

        let mut template: TemplateConfig = ConfigFile::load(template_path).unwrap();
        let keychain: KeyConfig = ConfigFile::load(keychain_path).unwrap();
        let addr = format!("{}:{}", Self::addr(matches),
                     Self::port(matches).unwrap_or(DEFAULT_EXONUM_LISTEN_PORT))
                     .parse()
                     .unwrap();
        if !template.validators.contains_key(&keychain.public_key) {
            if template.validators.len() >= template.count {
                panic!("This template alredy full.");
            }
            let ident = ValidatorIdent {
                addr: addr
            };
            template.validators.insert(keychain.public_key, ident);
        }
        else {
            panic!("This node alredy in template");
        }

        ConfigFile::save(&template, template_path).unwrap();
    }
}

pub struct InitCommand;

impl InitCommand
{
    pub fn new<'a>() -> App<'a, 'a> {
        SubCommand::with_name("init")
            .about("Toolchain to generate configuration")
            .arg(Arg::with_name("FULL_TEMPLATE")
                     .help("Path to full template")
                     .required(true)
                     .index(1))
            .arg(Arg::with_name("KEYCHAIN")
                     .help("Path to keychain config.")
                     .required(true)
                     .index(2))
            .arg(Arg::with_name("CONFIG_PATH")
                     .help("Path to node config.")
                     .required(true)
                     .index(3))

    }

    pub fn template<'a>(matches: &'a ArgMatches<'a>) -> &'a Path {
        Path::new(matches.value_of("FULL_TEMPLATE").unwrap())
    }

    pub fn config<'a>(matches: &'a ArgMatches<'a>) -> &'a Path {
        Path::new(matches.value_of("CONFIG_PATH").unwrap())
    }

    pub fn keychain<'a>(matches: &'a ArgMatches<'a>) -> &'a Path {
        Path::new(matches.value_of("KEYCHAIN").unwrap())
    }

    pub fn execute_default(matches: &ArgMatches) {
        let config_path = Self::config(matches);
        let template_path = Self::template(matches);
        let keychain_path = Self::keychain(matches);

        let template: TemplateConfig = ConfigFile::load(template_path).unwrap();
        let keychain: KeyConfig = ConfigFile::load(keychain_path).unwrap();

        if template.validators.len() != template.count {
            panic!("Template should be full.");
        }

        let genesis = GenesisConfig::new(template.validators.iter().map(|(k,_)| *k));
        let peers = template.validators.iter().map(|(_,ident)| ident.addr).collect();
        let validator_ident = &template.validators[&keychain.public_key];

        let config =  NodeConfig {
            listen_address: validator_ident.addr,
            network: Default::default(),
            peers: peers,
            public_key: keychain.public_key,
            secret_key: keychain.secret_key,
            genesis: genesis,
        };

        ConfigFile::save(&config, config_path).unwrap();
    }

}

pub struct GenerateCommand<'a, 'b>
    where 'a: 'b
{
    _p: PhantomData<App<'a, 'b>>,
}

<commit_msg>revert generate testnet command, refactor.<commit_after>
use clap::{SubCommand, App, Arg, ArgMatches};

use std::path::Path;
use std::fs;
use std::marker::PhantomData;
use std::collections::BTreeMap;
use std::net::SocketAddr;
use std::error::Error;

use config::ConfigFile;
use blockchain::{ConsensusConfig, GenesisConfig};
use node::NodeConfig;
use storage::Storage;
use crypto::{self, PublicKey, SecretKey};
use super::generate_testnet_config;

const DEFAULT_EXONUM_LISTEN_PORT: u16 = 6333;

#[derive(Debug)]
pub struct RunCommand<'a, 'b>
    where 'a: 'b
{
    _p: PhantomData<App<'a, 'b>>,
}

impl<'a, 'b> RunCommand<'a, 'b>
    where 'a: 'b
{
    pub fn new() -> App<'a, 'b> {
        SubCommand::with_name("run")
            .about("Run node with given configuration")
            .arg(Arg::with_name("NODE_CONFIG_PATH")
                     .short("c")
                     .long("node-config")
                     .value_name("NODE_CONFIG_PATH")
                     .help("Path to node configuration file")
                     .required(true)
                     .takes_value(true))
            .arg(Arg::with_name("LEVELDB_PATH")
                     .short("d")
                     .long("leveldb-path")
                     .value_name("LEVELDB_PATH")
                     .help("Use leveldb database with the given path")
                     .required(false)
                     .takes_value(true))
            .arg(Arg::with_name("PUBLIC_API_ADDRESS")
                     .long("public-api-address")
                     .help("Listen address for public api")
                     .required(false)
                     .takes_value(true))
            .arg(Arg::with_name("PRIVATE_API_ADDRESS")
                     .long("private-api-address")
                     .help("Listen address for private api")
                     .required(false)
                     .takes_value(true))
    }

    pub fn node_config_path(matches: &'a ArgMatches<'a>) -> &'a Path {
        matches
            .value_of("NODE_CONFIG_PATH")
            .map(Path::new)
            .expect("Path to node configuration is no setted")
    }

    pub fn node_config(matches: &'a ArgMatches<'a>) -> NodeConfig {
        let path = Self::node_config_path(matches);
        let mut cfg: NodeConfig = ConfigFile::load(path).unwrap();
        // Override api options
        if let Some(addr) = Self::public_api_address(matches) {
            cfg.api.public_api_address = Some(addr);
        }
        if let Some(addr) = Self::private_api_address(matches) {
            cfg.api.private_api_address = Some(addr);
        }
        cfg
    }

    pub fn public_api_address(matches: &'a ArgMatches<'a>) -> Option<SocketAddr> {
        matches
            .value_of("PUBLIC_API_ADDRESS")
            .map(|s| {
                     s.parse()
                         .expect("Public api address has incorrect format")
                 })
    }

    pub fn private_api_address(matches: &'a ArgMatches<'a>) -> Option<SocketAddr> {
        matches
            .value_of("PRIVATE_API_ADDRESS")
            .map(|s| {
                     s.parse()
                         .expect("Private api address has incorrect format")
                 })
    }

    pub fn leveldb_path(matches: &'a ArgMatches<'a>) -> Option<&'a Path> {
        matches.value_of("LEVELDB_PATH").map(Path::new)
    }

    #[cfg(not(feature="memorydb"))]
    pub fn db(matches: &'a ArgMatches<'a>) -> Box<Database> {
        use storage::{LevelDB, LevelDBOptions};

        let path = Self::leveldb_path(matches).unwrap();
        let mut options = LevelDBOptions::new();
        options.create_if_missing = true;
        Box::new(LevelDB::open(path, options).unwrap())
    }

    #[cfg(feature="memorydb")]
    pub fn db(_: &'a ArgMatches<'a>) -> Box<Database> {
        use storage::MemoryDB;
        Box::new(MemoryDB::new())
    }
}

#[derive(Serialize, Deserialize)]
pub struct ValidatorIdent {
    pub values: BTreeMap<String, String>,
    addr: SocketAddr,
}

#[derive(Serialize, Deserialize, Default)]
pub struct ConfigTemplate {
    validators: BTreeMap<PublicKey, ValidatorIdent>,
    consensus_cfg: ConsensusConfig,
    count: usize,
    services: BTreeMap<String, String>,
}

#[derive(Serialize, Deserialize)]
pub struct KeyConfig {
    public_key: PublicKey,
    secret_key: SecretKey,
}

pub struct KeyGeneratorCommand;

impl KeyGeneratorCommand {
    /// Creates basic keygen subcommand.
    pub fn new<'a>() -> App<'a, 'a> {
        SubCommand::with_name("keygen")
            .about("Generate basic node secret key.")
            .arg(Arg::with_name("KEYCHAIN")
                     .help("Path to key config.")
                     .required(true)
                     .index(1))
    }

    /// Path where keychain config should be saved
    pub fn keychain<'a>(matches: &'a ArgMatches<'a>) -> &'a Path {
        Path::new(matches.value_of("KEYCHAIN").unwrap())
    }

    /// Generates and writes key config to `keychain()` path.
    pub fn execute_default(matches: &ArgMatches) {
        let (pub_key, sec_key) = crypto::gen_keypair();
        let keyconfig = Self::keychain(matches);
        let pub_key_path = keyconfig.with_extension("pub");

        // save pub_key seperately
        ConfigFile::save(&pub_key, &pub_key_path).unwrap();

        let config = KeyConfig {
            public_key: pub_key,
            secret_key: sec_key,
        };

        ConfigFile::save(&config, Self::keychain(matches)).unwrap();
    }
}

/// implement command for template generating
pub struct GenerateTemplateCommand;
impl GenerateTemplateCommand {
    pub fn new<'a>() -> App<'a, 'a> {
        SubCommand::with_name("generate-template")
            .about("Generate basic template.")
            .arg(Arg::with_name("COUNT")
                     .help("Validator total count.")
                     .required(true)
                     .index(1))
            .arg(Arg::with_name("TEMPLATE")
                     .help("Path to template config.")
                     .required(true)
                     .index(2))
    }

    /// Path where template config should be saved
    pub fn template<'a>(matches: &'a ArgMatches<'a>) -> &'a Path {
        Path::new(matches.value_of("TEMPLATE").unwrap())
    }
    /// Validator total count
    pub fn count(matches: &ArgMatches) -> usize {
        matches.value_of("COUNT").unwrap().parse().unwrap()
    }

    /// Write default template config into `template()` path.
    pub fn execute<T>(matches: &ArgMatches, values: T)
        where T: Into<Option<BTreeMap<String, String>>>
    {
        let values = values.into().unwrap_or_default();
        let template = ConfigTemplate {
            count: Self::count(matches),
            services: values,
            ..ConfigTemplate::default()
        };

        ConfigFile::save(&template, Self::template(matches)).unwrap();
    }
}

pub struct AddValidatorCommand;
impl AddValidatorCommand {
    pub fn new<'a>() -> App<'a, 'a> {
        SubCommand::with_name("add-validator")
            .about("Preinit configuration, add validator to config template.")
            .arg(Arg::with_name("TEMPLATE")
                     .help("Path to template")
                     .required(true)
                     .index(1))
            .arg(Arg::with_name("PUBLIC_KEY")
                     .help("Path to public key file.")
                     .required(true)
                     .index(2))
            .arg(Arg::with_name("LISTEN_ADDR")
                     .short("a")
                     .long("listen-addr")
                     .value_name("LISTEN_ADDR")
                     .required(true)
                     .takes_value(true))
            .arg(Arg::with_name("PORT")
                     .short("p")
                     .long("port")
                     .value_name("PORT")
                     .required(false)
                     .takes_value(true))

    }

    /// path to public_key file
    pub fn public_key<'a>(matches: &'a ArgMatches<'a>) -> &'a Path {
        Path::new(matches.value_of("PUBLIC_KEY").unwrap())
    }

    /// path to template config
    pub fn template<'a>(matches: &'a ArgMatches<'a>) -> &'a Path {
        Path::new(matches.value_of("TEMPLATE").unwrap())
    }

    // exonum listen port
    pub fn port(matches: &ArgMatches) -> Option<u16> {
        matches
            .value_of("PORT")
            .and_then(|port| port.parse().ok())
    }

    // exonum listen addr
    pub fn addr(matches: &ArgMatches) -> String {
        matches.value_of("LISTEN_ADDR").unwrap().to_string()
    }

    #[cfg_attr(feature="cargo-clippy", allow(map_entry))]
    pub fn execute<F, X>(matches: &ArgMatches, on_add: F)
        where F: Into<Option<X>>,
              X: FnOnce(usize, &mut BTreeMap<String, String>)
                        -> Result<BTreeMap<String, String>, Box<Error>>
    {
        let template_path = Self::template(matches);
        let public_key_path = Self::public_key(matches);

        let mut template: ConfigTemplate = ConfigFile::load(template_path).unwrap();
        let public_key: PublicKey = ConfigFile::load(public_key_path).unwrap();
        let addr = format!("{}:{}",
                           Self::addr(matches),
                           Self::port(matches).unwrap_or(DEFAULT_EXONUM_LISTEN_PORT))
                .parse()
                .unwrap();
        if !template.validators.contains_key(&public_key) {
            if template.validators.len() >= template.count {
                panic!("This template alredy full.");
            }
            let func = on_add
                .into()
                .map(|f| f(template.count, &mut template.services));
            let map = func.unwrap_or_else(|| Ok(BTreeMap::new()));

            let ident = ValidatorIdent {
                addr: addr,
                values: map.unwrap(),
            };
            template.validators.insert(public_key, ident);
        } else {
            panic!("This node alredy in template");
        }

        ConfigFile::save(&template, template_path).unwrap();
    }
}

pub struct InitCommand;

impl InitCommand {
    pub fn new<'a>() -> App<'a, 'a> {
        SubCommand::with_name("init")
            .about("Toolchain to generate configuration")
            .arg(Arg::with_name("FULL_TEMPLATE")
                     .help("Path to full template")
                     .required(true)
                     .index(1))
            .arg(Arg::with_name("KEYCHAIN")
                     .help("Path to keychain config.")
                     .required(true)
                     .index(2))
            .arg(Arg::with_name("CONFIG_PATH")
                     .help("Path to node config.")
                     .required(true)
                     .index(3))

    }

    /// path to full template config
    pub fn template<'a>(matches: &'a ArgMatches<'a>) -> &'a Path {
        Path::new(matches.value_of("FULL_TEMPLATE").unwrap())
    }

    /// path to output config
    pub fn config<'a>(matches: &'a ArgMatches<'a>) -> &'a Path {
        Path::new(matches.value_of("CONFIG_PATH").unwrap())
    }

    /// path to keychain (public and secret keys)
    pub fn keychain<'a>(matches: &'a ArgMatches<'a>) -> &'a Path {
        Path::new(matches.value_of("KEYCHAIN").unwrap())
    }

    pub fn execute<F, X>(matches: &ArgMatches, on_init: F)
        where F: Into<Option<X>>,
              X: FnOnce(&BTreeMap<String, String>,
                        &BTreeMap<PublicKey, ValidatorIdent>)
                        -> Result<(), Box<Error>>
    {
        let config_path = Self::config(matches);
        let template_path = Self::template(matches);
        let keychain_path = Self::keychain(matches);

        let template: ConfigTemplate = ConfigFile::load(template_path).unwrap();
        let keychain: KeyConfig = ConfigFile::load(keychain_path).unwrap();

        if template.validators.len() != template.count {
            panic!("Template should be full.");
        }

        let func = on_init
            .into()
            .map(|f| f(&template.services, &template.validators));
        let func = func.unwrap_or(Ok(()));
        // propogate error
        func.unwrap();

        let genesis = GenesisConfig::new(template.validators.iter().map(|(k, _)| *k));
        let peers = template
            .validators
            .iter()
            .map(|(_, ident)| ident.addr)
            .collect();
        let validator_ident = &template.validators[&keychain.public_key];

        let config = NodeConfig {
            listen_address: validator_ident.addr,
            network: Default::default(),
            peers: peers,
            public_key: keychain.public_key,
            secret_key: keychain.secret_key,
            genesis: genesis,
            api: Default::default(),
        };

        ConfigFile::save(&config, config_path).unwrap();
    }
}

pub struct GenerateTestnetCommand;

impl GenerateTestnetCommand {
    pub fn new<'a>() -> App<'a, 'a> {
        SubCommand::with_name("generate")
            .about("Generates genesis configuration")
            .arg(Arg::with_name("OUTPUT_DIR")
                     .short("o")
                     .long("output-dir")
                     .value_name("OUTPUT_DIR")
                     .required(true)
                     .takes_value(true))
            .arg(Arg::with_name("START_PORT")
                     .short("p")
                     .long("start-port")
                     .value_name("START_PORT")
                     .required(false)
                     .takes_value(true))
            .arg(Arg::with_name("COUNT")
                     .help("Validators count")
                     .required(true)
                     .index(1))
    }

    pub fn output_dir<'a>(matches: &'a ArgMatches<'a>) -> &'a Path {
        Path::new(matches.value_of("OUTPUT_DIR").unwrap())
    }

    pub fn validators_count(matches: &ArgMatches) -> u8 {
        matches.value_of("COUNT").unwrap().parse().unwrap()
    }

    pub fn start_port(matches: &ArgMatches) -> Option<u16> {
        matches
            .value_of("START_PORT")
            .map(|p| p.parse().unwrap())
    }

    pub fn execute<'a>(matches: &'a ArgMatches<'a>) {
        let dir = Self::output_dir(matches);
        let count = Self::validators_count(matches);
        let start_port = Self::start_port(matches).unwrap_or_else(|| 2000);

        let dir = dir.join("validators");
        if !dir.exists() {
            fs::create_dir_all(&dir).unwrap();
        }

        let configs = generate_testnet_config(count, start_port);
        for (idx, cfg) in configs.into_iter().enumerate() {
            let file_name = format!("{}.toml", idx);
            ConfigFile::save(&cfg, &dir.join(file_name)).unwrap();
        }
    }
}
<|endoftext|>


<commit_before>use crate::command_prelude::*;

use cargo::ops::{self, CompileFilter};

pub fn cli() -> App {
    subcommand("test")
        // subcommand aliases are handled in aliased_command()
        // .alias("t")
        .setting(AppSettings::TrailingVarArg)
        .about("Execute all unit and integration tests of a local package")
        .arg(
            Arg::with_name("TESTNAME")
                .help("If specified, only run tests containing this string in their names"),
        )
        .arg(
            Arg::with_name("args")
                .help("Arguments for the test binary")
                .multiple(true)
                .last(true),
        )
        .arg_targets_all(
            "Test only this package's library",
            "Test only the specified binary",
            "Test all binaries",
            "Test only the specified example",
            "Test all examples",
            "Test only the specified test target",
            "Test all tests",
            "Test only the specified bench target",
            "Test all benches",
            "Test all targets",
        )
        .arg(opt("doc", "Test only this library's documentation"))
        .arg(opt("no-run", "Compile, but don't run tests"))
        .arg(opt("no-fail-fast", "Run all tests regardless of failure"))
        .arg_package_spec(
            "Package to run tests for",
            "Test all packages in the workspace",
            "Exclude packages from the test",
        )
        .arg_jobs()
        .arg_release("Build artifacts in release mode, with optimizations")
        .arg_features()
        .arg_target_triple("Build for the target triple")
        .arg_target_dir()
        .arg_manifest_path()
        .arg_message_format()
        .after_help(
            "\
The test filtering argument `TESTNAME` and all the arguments following the
two dashes (`--`) are passed to the test binaries and thus to libtest
(rustc's built in unit-test and micro-benchmarking framework).  If you're
passing arguments to both Cargo and the binary, the ones after `--` go to the
binary, the ones before go to Cargo.  For details about libtest's arguments see
the output of `cargo test -- --help`.  As an example, this will run all
tests with `foo` in their name on 3 threads in parallel:

    cargo test foo -- --test-threads 3

If the --package argument is given, then SPEC is a package id specification
which indicates which package should be tested. If it is not given, then the
current package is tested. For more information on SPEC and its format, see the
`cargo help pkgid` command.

All packages in the workspace are tested if the `--all` flag is supplied. The
`--all` flag is automatically assumed for a virtual manifest.
Note that `--exclude` has to be specified in conjunction with the `--all` flag.

The --jobs argument affects the building of the test executable but does
not affect how many jobs are used when running the tests. The default value
for the --jobs argument is the number of CPUs. If you want to control the
number of simultaneous running test cases, pass the `--test-threads` option
to the test binaries:

    cargo test -- --test-threads=1

Compilation can be configured via the `test` profile in the manifest.

By default the rust test harness hides output from test execution to
keep results readable. Test output can be recovered (e.g. for debugging)
by passing `--nocapture` to the test binaries:

    cargo test -- --nocapture

To get the list of all options available for the test binaries use this:

    cargo test -- --help
",
        )
}

pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
    let ws = args.workspace(config)?;

    let mut compile_opts = args.compile_options(config, CompileMode::Test, Some(&ws))?;

    let no_run = args.is_present("no-run");
    let doc = args.is_present("doc");
    if doc {
        if let CompileFilter::Only { .. } = compile_opts.filter {
            return Err(CliError::new(
                failure::format_err!("Can't mix --doc with other target selecting options"),
                101,
            ));
        }
        if no_run {
            return Err(CliError::new(
                failure::format_err!("Can't skip running doc tests with --no-run"),
                101,
            ));
        }
        compile_opts.build_config.mode = CompileMode::Doctest;
        compile_opts.filter = ops::CompileFilter::new(
            true,
            Vec::new(),
            false,
            Vec::new(),
            false,
            Vec::new(),
            false,
            Vec::new(),
            false,
            false,
        );
    }

    let ops = ops::TestOptions {
        no_run,
        no_fail_fast: args.is_present("no-fail-fast"),
        compile_opts,
    };

    // TESTNAME is actually an argument of the test binary, but it's
    // important so we explicitly mention it and reconfigure
    let mut test_args = vec![];
    test_args.extend(args.value_of("TESTNAME").into_iter().map(|s| s.to_string()));
    test_args.extend(
        args.values_of("args")
            .unwrap_or_default()
            .map(|s| s.to_string()),
    );

    let err = ops::run_tests(&ws, &ops, &test_args)?;
    match err {
        None => Ok(()),
        Some(err) => Err(match err.exit.as_ref().and_then(|e| e.code()) {
            Some(i) => CliError::new(failure::format_err!("{}", err.hint(&ws)), i),
            None => CliError::new(err.into(), 101),
        }),
    }
}
<commit_msg>Auto merge of #6619 - dwijnand:cargo-test-help, r=ehuss<commit_after>use crate::command_prelude::*;

use cargo::ops::{self, CompileFilter};

pub fn cli() -> App {
    subcommand("test")
        // subcommand aliases are handled in aliased_command()
        // .alias("t")
        .setting(AppSettings::TrailingVarArg)
        .about("Execute all unit and integration tests and build examples of a local package")
        .arg(
            Arg::with_name("TESTNAME")
                .help("If specified, only run tests containing this string in their names"),
        )
        .arg(
            Arg::with_name("args")
                .help("Arguments for the test binary")
                .multiple(true)
                .last(true),
        )
        .arg_targets_all(
            "Test only this package's library unit tests",
            "Test only the specified binary",
            "Test all binaries",
            "Test only the specified example",
            "Test all examples",
            "Test only the specified test target",
            "Test all tests",
            "Test only the specified bench target",
            "Test all benches",
            "Test all targets",
        )
        .arg(opt("doc", "Test only this library's documentation"))
        .arg(opt("no-run", "Compile, but don't run tests"))
        .arg(opt("no-fail-fast", "Run all tests regardless of failure"))
        .arg_package_spec(
            "Package to run tests for",
            "Test all packages in the workspace",
            "Exclude packages from the test",
        )
        .arg_jobs()
        .arg_release("Build artifacts in release mode, with optimizations")
        .arg_features()
        .arg_target_triple("Build for the target triple")
        .arg_target_dir()
        .arg_manifest_path()
        .arg_message_format()
        .after_help(
            "\
The test filtering argument `TESTNAME` and all the arguments following the
two dashes (`--`) are passed to the test binaries and thus to libtest
(rustc's built in unit-test and micro-benchmarking framework).  If you're
passing arguments to both Cargo and the binary, the ones after `--` go to the
binary, the ones before go to Cargo.  For details about libtest's arguments see
the output of `cargo test -- --help`.  As an example, this will run all
tests with `foo` in their name on 3 threads in parallel:

    cargo test foo -- --test-threads 3

If the --package argument is given, then SPEC is a package id specification
which indicates which package should be tested. If it is not given, then the
current package is tested. For more information on SPEC and its format, see the
`cargo help pkgid` command.

All packages in the workspace are tested if the `--all` flag is supplied. The
`--all` flag is automatically assumed for a virtual manifest.
Note that `--exclude` has to be specified in conjunction with the `--all` flag.

The --jobs argument affects the building of the test executable but does
not affect how many jobs are used when running the tests. The default value
for the --jobs argument is the number of CPUs. If you want to control the
number of simultaneous running test cases, pass the `--test-threads` option
to the test binaries:

    cargo test -- --test-threads=1

Compilation can be configured via the `test` profile in the manifest.

By default the rust test harness hides output from test execution to
keep results readable. Test output can be recovered (e.g. for debugging)
by passing `--nocapture` to the test binaries:

    cargo test -- --nocapture

To get the list of all options available for the test binaries use this:

    cargo test -- --help
",
        )
}

pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
    let ws = args.workspace(config)?;

    let mut compile_opts = args.compile_options(config, CompileMode::Test, Some(&ws))?;

    let no_run = args.is_present("no-run");
    let doc = args.is_present("doc");
    if doc {
        if let CompileFilter::Only { .. } = compile_opts.filter {
            return Err(CliError::new(
                failure::format_err!("Can't mix --doc with other target selecting options"),
                101,
            ));
        }
        if no_run {
            return Err(CliError::new(
                failure::format_err!("Can't skip running doc tests with --no-run"),
                101,
            ));
        }
        compile_opts.build_config.mode = CompileMode::Doctest;
        compile_opts.filter = ops::CompileFilter::new(
            true,
            Vec::new(),
            false,
            Vec::new(),
            false,
            Vec::new(),
            false,
            Vec::new(),
            false,
            false,
        );
    }

    let ops = ops::TestOptions {
        no_run,
        no_fail_fast: args.is_present("no-fail-fast"),
        compile_opts,
    };

    // TESTNAME is actually an argument of the test binary, but it's
    // important so we explicitly mention it and reconfigure
    let mut test_args = vec![];
    test_args.extend(args.value_of("TESTNAME").into_iter().map(|s| s.to_string()));
    test_args.extend(
        args.values_of("args")
            .unwrap_or_default()
            .map(|s| s.to_string()),
    );

    let err = ops::run_tests(&ws, &ops, &test_args)?;
    match err {
        None => Ok(()),
        Some(err) => Err(match err.exit.as_ref().and_then(|e| e.code()) {
            Some(i) => CliError::new(failure::format_err!("{}", err.hint(&ws)), i),
            None => CliError::new(err.into(), 101),
        }),
    }
}
<|endoftext|>


<commit_before>use std::sync::{Arc, RwLock};
use app::M;
use plugin1::{Plugin1Options, Plugin1};
use plugin2::Plugin2;
use pluginbuilder::{Plugin, PluginWithOptions};
use std::thread;
use std::thread::JoinHandle;

pub type AppRef = Arc<RwLock<M>>;

pub enum Plugins {
    Plugin1(Plugin1Options),
    Plugin2,
}

pub struct Pluggable {
    app: AppRef,
    plugins: Arc<RwLock<Vec<Box<Plugin>>>>,
    is_running: Arc<RwLock<bool>>,
}

impl Clone for Pluggable {
    fn clone(&self) -> Self {
        Pluggable {
            app: self.app.clone(),
            plugins: self.plugins.clone(),
            is_running: self.is_running.clone(),
        }
    }
}

impl Pluggable {
    pub fn new(app: M) -> Self {
        Pluggable {
            app: Arc::new(RwLock::new(app)),
            plugins: Arc::new(RwLock::new(vec![])),
            is_running: Arc::new(RwLock::new(true)),
        }
    }

    pub fn load_plugin(&mut self, pl_name: Plugins) {
        let plugin: Box<Plugin> = match pl_name {
            Plugins::Plugin1(opts) => {
                let mut p = Plugin1::new(self.app.clone());
                p.init(opts);
                Box::new(p)
            }

            Plugins::Plugin2 => Box::new(Plugin2::new()),
        };
        self.plugins.write().unwrap().push(plugin);
    }

    pub fn run_app(&mut self) {
        let self_clone = self.clone();
        thread::spawn(move || {
            while *self_clone.is_running.read().unwrap() {
                self_clone.app
                    .write()
                    .expect("Cant run app!")
                    .run();
                thread::yield_now();
            }
        });
    }

    pub fn run_plugins(&mut self) {
        let self_clone = self.clone();
        thread::spawn(move || {
            while *self_clone.is_running.read().unwrap() {
                for pl in self_clone.plugins.write().unwrap().iter_mut() {
                    pl.run();
                }
                thread::yield_now();
            }
        });
    }

    pub fn stop(&mut self) {
        *self.is_running.write().unwrap() = false;
        for pl in self.plugins.write().unwrap().iter_mut() {
            pl.stop();
        }
    }
}
<commit_msg>refactoring<commit_after>use std::sync::{Arc, RwLock};
use app::M;
use plugin1::{Plugin1Options, Plugin1};
use plugin2::Plugin2;
use pluginbuilder::{Plugin, PluginWithOptions};
use std::thread;

pub type AppRef = Arc<RwLock<M>>;

pub enum Plugins {
    Plugin1(Plugin1Options),
    Plugin2,
}

#[derive(Clone)]
pub struct Pluggable {
    app: AppRef,
    plugins: Arc<RwLock<Vec<Box<Plugin>>>>,
    is_running: Arc<RwLock<bool>>,
}

impl Pluggable {
    pub fn new(app: M) -> Self {
        Pluggable {
            app: Arc::new(RwLock::new(app)),
            plugins: Arc::new(RwLock::new(vec![])),
            is_running: Arc::new(RwLock::new(true)),
        }
    }

    pub fn load_plugin(&mut self, pl_name: Plugins) {
        let plugin: Box<Plugin> = match pl_name {
            Plugins::Plugin1(opts) => {
                let mut p = Plugin1::new(self.app.clone());
                p.init(opts);
                Box::new(p)
            }

            Plugins::Plugin2 => Box::new(Plugin2::new()),
        };
        self.plugins.write().unwrap().push(plugin);
    }

    pub fn run_app(&mut self) {
        let self_clone = self.clone();
        thread::spawn(move || {
            while *self_clone.is_running.read().unwrap() {
                self_clone.app
                    .write()
                    .expect("Cant run app!")
                    .run();
                thread::yield_now();
            }
        });
    }

    pub fn run_plugins(&mut self) {
        let self_clone = self.clone();
        thread::spawn(move || {
            while *self_clone.is_running.read().unwrap() {
                for pl in self_clone.plugins.write().unwrap().iter_mut() {
                    pl.run();
                }
                thread::yield_now();
            }
        });
    }

    pub fn stop(&mut self) {
        *self.is_running.write().unwrap() = false;
        for pl in self.plugins.write().unwrap().iter_mut() {
            pl.stop();
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2017 CoreOS, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! retry is a generic function that retrys functions until they succeed.

use crate::errors::*;
use std::thread;
use std::time::Duration;

mod client;
pub mod raw_deserializer;
pub use self::client::*;

#[derive(Clone, Debug)]
pub struct Retry {
    initial_backoff: Duration,
    max_backoff: Duration,
    max_attempts: u32,
}

impl ::std::default::Default for Retry {
    fn default() -> Self {
        Retry {
            initial_backoff: Duration::new(1, 0),
            max_backoff: Duration::new(5, 0),
            max_attempts: 10,
        }
    }
}

impl Retry {
    pub fn new() -> Self {
        Retry::default()
    }

    pub fn initial_backoff(mut self, initial_backoff: Duration) -> Self {
        self.initial_backoff = initial_backoff;
        self
    }

    pub fn max_backoff(mut self, max_backoff: Duration) -> Self {
        self.max_backoff = max_backoff;
        self
    }

    pub fn max_attempts(mut self, max_attempts: u32) -> Self {
        self.max_attempts = max_attempts;
        self
    }

    pub fn retry<F, R>(self, try_fn: F) -> Result<R>
    where
        F: Fn(u32) -> Result<R>,
    {
        let mut delay = self.initial_backoff;
        let mut attempts = 0;

        loop {
            let res = try_fn(attempts);

            // if the result is ok, we don't need to try again
            if res.is_ok() {
                break res;
            }

            // otherwise, perform the retry-backoff logic
            attempts += 1;
            if attempts == self.max_attempts {
                break res.map_err(|e| Error::with_chain(e, "timed out"));
            }

            thread::sleep(delay);

            delay = if self.max_backoff != Duration::new(0, 0) && delay * 2 > self.max_backoff {
                self.max_backoff
            } else {
                delay * 2
            };
        }
    }
}
<commit_msg>retry: minor cleanups<commit_after>// Copyright 2017 CoreOS, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Drive a functions through a finite number of retries until it succeeds.

use crate::errors::*;
use std::thread;
use std::time::Duration;

mod client;
pub mod raw_deserializer;
pub use self::client::*;

#[derive(Clone, Debug)]
pub struct Retry {
    initial_backoff: Duration,
    max_backoff: Duration,
    max_retries: u32,
}

impl Default for Retry {
    fn default() -> Self {
        Retry {
            initial_backoff: Duration::new(1, 0),
            max_backoff: Duration::new(5, 0),
            max_retries: 10,
        }
    }
}

impl Retry {
    /// Build a new retrying driver.
    ///
    /// This defaults to 10 retries with 5 seconds maximum backoff.
    pub fn new() -> Self {
        Retry::default()
    }

    /// Set the initial backoff.
    pub fn initial_backoff(mut self, initial_backoff: Duration) -> Self {
        self.initial_backoff = initial_backoff;
        self
    }

    /// Set the maximum backoff.
    pub fn max_backoff(mut self, max_backoff: Duration) -> Self {
        self.max_backoff = max_backoff;
        self
    }

    /// Maximum number of retries to attempt.
    ///
    /// If zero, only the initial run will be performed, with no
    /// additional retries.
    pub fn max_attempts(mut self, retries: u32) -> Self {
        self.max_retries = retries;
        self
    }

    /// Retry a function until it either succeeds once or fails all the time.
    pub fn retry<F, R>(self, try_fn: F) -> Result<R>
    where
        F: Fn(u32) -> Result<R>,
    {
        let mut delay = self.initial_backoff;
        let mut attempts = 0;

        loop {
            let res = try_fn(attempts);

            // If the result is ok, there is no need to try again.
            if res.is_ok() {
                break res;
            }

            // Otherwise, perform "the retry with backoff" logic.
            if attempts >= self.max_retries {
                let msg = format!("maximum number of retries ({}) reached", self.max_retries);
                break res.map_err(|e| Error::with_chain(e, msg.as_str()));
            }
            attempts = attempts.saturating_add(1);

            thread::sleep(delay);

            delay = if self.max_backoff != Duration::new(0, 0) && delay * 2 > self.max_backoff {
                self.max_backoff
            } else {
                delay * 2
            };
        }
    }
}
<|endoftext|>


<commit_before>use core::prelude::*;
use core::default::Default;
use boxed::Box;
use fn_box::FnBox;
use collections::RingBuf;
use global::global;
use alloc::heap::allocate;

pub fn spawn<F, R>(f:F) -> Future<R> where F: FnOnce()->R, F:Send {
    global().scheduler.lock().spawn(f)
}

pub unsafe fn reschedule(current_rsp: uint) -> ! {

    // switch stack so we can park current thread
    const SCHEDULER_STACK_SIZE: uint = 4096;
    static SCHEDULER_STACK: [u8; SCHEDULER_STACK_SIZE] = [0; SCHEDULER_STACK_SIZE];

    let scheduler_stack_top = &SCHEDULER_STACK as *const [u8; 4096] as uint
        + SCHEDULER_STACK_SIZE;
    call_on_stack(inner, current_rsp, scheduler_stack_top);

    fn inner(current_rsp: uint) -> ! {
        extern {
            fn pop_registers_and_iret(rsp: uint) -> !;
        }

        // park current thread
        let current = Thread::from_rsp(current_rsp);
        global().scheduler.lock().park(current);

        // schedule new thread
        loop {
            print!("_");
            let new_thread = unsafe{global().scheduler.lock().schedule().unwrap_or_default()};
            match new_thread {
                Thread{state: ThreadState::Active{rsp}} => {
                    unsafe{pop_registers_and_iret(rsp)}
                },
                Thread{state: ThreadState::New{function}} => {
                    print!("new");
                    let new_stack_top = new_stack();
                    // TODO new stack
                    function.call_once(())
                },
            }
        }
    }

}

fn new_stack() -> uint {
    const NEW_STACK_SIZE: uint = 4096*2;
    let stack_bottom = unsafe{allocate(NEW_STACK_SIZE, 4096)};
    let stack_top = (stack_bottom as uint + NEW_STACK_SIZE);
    stack_top
}

fn call_on_stack<Arg>(function: fn(Arg) -> !, arg: Arg, stack_top: uint) -> ! {
    unsafe{asm!("call $0;" :: "r"(function), "{rdi}"(arg), "{rsp}"(stack_top) :: "intel")}
    panic!("diverging fn returned");
}

pub type GlobalScheduler = Scheduler;
impl GlobalScheduler {
    pub fn new() -> GlobalScheduler {
        Scheduler::new()
    }
}

pub struct Future<T>;

pub struct Thread {
    state: ThreadState,
}

impl Thread {
    fn new<F>(f: F) -> Thread where F : FnOnce(), F: Send {
        Thread {
            state: ThreadState::New {
                function: box f,
            }
        }
    }

    pub fn from_rsp(rsp: uint) -> Thread {
        Thread {
            state: ThreadState::Active {
                rsp: rsp,
            }
        }
    }
}

impl Default for Thread {
    fn default() -> Thread {
        Thread::new(|| print!("."))
    }
}

enum ThreadState {
    New {
        function: Box<FnBox() + Send>,
    },
    Active {
        rsp: uint,
    }
}

pub struct Scheduler {
    threads: RingBuf<Thread>,
}

impl Scheduler {
    pub fn new() -> Scheduler {
        Scheduler{
            threads: RingBuf::new(),
        }
    }

    fn spawn<F, R>(&mut self, f:F) -> Future<R> where F: FnOnce()->R, F: Send {

        //let (tx, rx) = channel();

        self.threads.push_back(Thread::new(move |:| {
            /*tx.send_opt(*/ f();
        }));

        Future/*::from_receiver(rx)*/
    }

    fn park(&mut self, thread: Thread) {
        self.threads.push_back(thread)
    }

    unsafe fn schedule(&mut self) -> Option<Thread> {
        self.threads.pop_front()
    }
}<commit_msg>invoke new thread function on new stack<commit_after>use core::prelude::*;
use core::default::Default;
use boxed::Box;
use fn_box::FnBox;
use collections::RingBuf;
use global::global;
use alloc::heap::allocate;

pub fn spawn<F, R>(f:F) -> Future<R> where F: FnOnce()->R, F:Send {
    global().scheduler.lock().spawn(f)
}

pub unsafe fn reschedule(current_rsp: uint) -> ! {

    // switch stack so we can park current thread
    const SCHEDULER_STACK_SIZE: uint = 4096;
    static SCHEDULER_STACK: [u8; SCHEDULER_STACK_SIZE] = [0; SCHEDULER_STACK_SIZE];

    let scheduler_stack_top = &SCHEDULER_STACK as *const [u8; 4096] as uint
        + SCHEDULER_STACK_SIZE;
    call_on_stack(inner, current_rsp, scheduler_stack_top);

    fn new_stack() -> uint {
        const NEW_STACK_SIZE: uint = 4096*2;
        let stack_bottom = unsafe{allocate(NEW_STACK_SIZE, 4096)};
        let stack_top = (stack_bottom as uint + NEW_STACK_SIZE);
        stack_top
    }

    fn call_on_stack<Arg>(function: fn(Arg) -> !, arg: Arg, stack_top: uint) -> ! {
        unsafe{asm!("call $0;" :: "r"(function), "{rdi}"(arg), "{rsp}"(stack_top) :
            : "intel", "volatile")}
        panic!("diverging fn returned");
    }

    fn inner(current_rsp: uint) -> ! {
        extern {
            fn pop_registers_and_iret(rsp: uint) -> !;
        }

        // park current thread
        let current = Thread::from_rsp(current_rsp);
        global().scheduler.lock().park(current);

        // schedule new thread
        loop {
            print!("_");
            let new_thread = unsafe{global().scheduler.lock().schedule().unwrap_or_default()};
            match new_thread {
                Thread{state: ThreadState::Active{rsp}} => {
                    unsafe{pop_registers_and_iret(rsp)}
                },
                Thread{state: ThreadState::New{function}} => {
                    println!("new");
                    let new_stack_top = new_stack();
                    let invoke_fn : fn(Box<FnBox() + Send>) -> ! = invoke;
                    call_on_stack(invoke_fn, function, new_stack_top)
                },
            }
        }
    }

    fn invoke(function: Box<FnBox() + Send>) -> ! {
        function.call_once(());
        unsafe{asm!("int $$66" :::: "volatile")};
        unreachable!();
    }

}

pub type GlobalScheduler = Scheduler;
impl GlobalScheduler {
    pub fn new() -> GlobalScheduler {
        Scheduler::new()
    }
}

pub struct Future<T>;

pub struct Thread {
    state: ThreadState,
}

impl Thread {
    fn new<F>(f: F) -> Thread where F : FnOnce(), F: Send {
        Thread {
            state: ThreadState::New {
                function: box f,
            }
        }
    }

    pub fn from_rsp(rsp: uint) -> Thread {
        Thread {
            state: ThreadState::Active {
                rsp: rsp,
            }
        }
    }
}

impl Default for Thread {
    fn default() -> Thread {
        Thread::new(|| print!("."))
    }
}

enum ThreadState {
    New {
        function: Box<FnBox() + Send>,
    },
    Active {
        rsp: uint,
    }
}

pub struct Scheduler {
    threads: RingBuf<Thread>,
}

impl Scheduler {
    pub fn new() -> Scheduler {
        Scheduler{
            threads: RingBuf::new(),
        }
    }

    fn spawn<F, R>(&mut self, f:F) -> Future<R> where F: FnOnce()->R, F: Send {

        //let (tx, rx) = channel();

        self.threads.push_back(Thread::new(move |:| {
            /*tx.send_opt(*/ f();
        }));

        Future/*::from_receiver(rx)*/
    }

    fn park(&mut self, thread: Thread) {
        self.threads.push_back(thread)
    }

    unsafe fn schedule(&mut self) -> Option<Thread> {
        self.threads.pop_front()
    }
}<|endoftext|>


<commit_before>
pub mod sentiment {
    use std::collections::HashMap;
    use std::fs::File;
    use std::io::prelude::*;
    use std::io::BufReader;

    pub struct Analizer {
        wordlist: HashMap<String, i8>,
    }

    impl Analizer {
        pub fn analyze(&self, s: &str) -> f32 {
            let tokens = s.split(" ");
            let word_count = tokens.clone().count();

            let score = tokens.map(|word| word.to_string().to_lowercase())
                .map(|word| match self.wordlist.get(&word) {
                    Some(word_score) => *word_score,
                    None => 0 as i8,
                })
                .fold(0, |sum, curr| sum + curr);

            return score as f32 / word_count as f32;
        }
    }

    pub fn new(path: &str) -> Analizer {
        let mut wordlist = HashMap::new();

        let f = match File::open(&path) {
            Err(why) => panic!("couldn't open {}: {}", path, why),
            Ok(f) => f,
        };

        let f = BufReader::new(f);

        for line in f.lines() {
            let l = line.unwrap();
            let parts = l.split("\t").collect::<Vec<&str>>();

            let word = parts[0].to_string();
            let score = parts[1].parse::<i8>().unwrap();

            wordlist.insert(word, score);
        }

        return Analizer { wordlist: wordlist };
    }
}

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

    #[test]
    fn sentiment_test() {
        let analizer = sentiment::new("./src/wordlist.txt".to_string());
        assert!(analizer.analyze("Hey you worthless scumbag") == -1.5);
        assert!(analizer.analyze("I am happy") == 1 as f32);
        assert!(analizer.analyze("I am so happy") == 0.75);
        assert!(analizer.analyze("I am extremely happy") == 0.75 as f32);
        assert!(analizer.analyze("I am really sad") == -0.5 as f32);
    }
}
<commit_msg>Fix test string conversion<commit_after>
pub mod sentiment {
    use std::collections::HashMap;
    use std::fs::File;
    use std::io::prelude::*;
    use std::io::BufReader;

    pub struct Analizer {
        wordlist: HashMap<String, i8>,
    }

    impl Analizer {
        pub fn analyze(&self, s: &str) -> f32 {
            let tokens = s.split(" ");
            let word_count = tokens.clone().count();

            let score = tokens.map(|word| word.to_string().to_lowercase())
                .map(|word| match self.wordlist.get(&word) {
                    Some(word_score) => *word_score,
                    None => 0 as i8,
                })
                .fold(0, |sum, curr| sum + curr);

            return score as f32 / word_count as f32;
        }
    }

    pub fn new(path: &str) -> Analizer {
        let mut wordlist = HashMap::new();

        let f = match File::open(&path) {
            Err(why) => panic!("couldn't open {}: {}", path, why),
            Ok(f) => f,
        };

        let f = BufReader::new(f);

        for line in f.lines() {
            let l = line.unwrap();
            let parts = l.split("\t").collect::<Vec<&str>>();

            let word = parts[0].to_string();
            let score = parts[1].parse::<i8>().unwrap();

            wordlist.insert(word, score);
        }

        return Analizer { wordlist: wordlist };
    }
}

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

    #[test]
    fn sentiment_test() {
        let analizer = sentiment::new("./src/wordlist.txt");
        assert!(analizer.analyze("Hey you worthless scumbag") == -1.5);
        assert!(analizer.analyze("I am happy") == 1 as f32);
        assert!(analizer.analyze("I am so happy") == 0.75);
        assert!(analizer.analyze("I am extremely happy") == 0.75 as f32);
        assert!(analizer.analyze("I am really sad") == -0.5 as f32);
    }
}
<|endoftext|>


<commit_before>use std::fmt::{Display, Debug, Formatter};
use std::error::Error;
use std::borrow::Borrow;

use std::fmt;

macro_rules! errs {
    ($expr:expr, $($arg: tt)*) => ({
        $crate::std::result::Result::Err(
            $crate::error::StrError::new(format!($($arg)*),
                                         $crate::std::option::Option::Some(
                                             $crate::std::boxed::Box::new($expr))))
    })
}

pub type StrResult<T> = Result<T, StrError>;

pub struct StrError {
    description: String,
    cause: Option<Box<Error>>
}

impl Display for StrError {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        try!(write!(f, "{}", self.description()));
        match self.cause() {
            None => Ok(()),
            Some(error) => {
                write!(f, ": {}", error)
            }
        }
    }
}

impl Debug for StrError {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        Display::fmt(self, f)
    }
}

impl Error for StrError {
    fn description(&self) -> &str {
        self.description.as_ref()
    }

    fn cause(&self) -> Option<&Error> {
        match self.cause {
            None => None,
            Some(ref error) => Some(error.borrow())
        }
    }
}

impl StrError {
    pub fn new<T: Into<String>>(description: T, cause: Option<Box<Error>>) -> StrError {
        StrError {
            description: description.into(),
            cause: cause
        }
    }
}
<commit_msg>Missed a file<commit_after>// Copyright 2015 Jerome Rasky <jerome@rasky.co>
//
// Licensed under the Apache License, version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
//     <http://www.apache.org/licenses/LICENSE-2.0>
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either expressed or implied. See the
// License for the specific language concerning governing permissions and
// limitations under the License.
use std::fmt::{Display, Debug, Formatter};
use std::error::Error;
use std::borrow::Borrow;

use std::fmt;

macro_rules! errs {
    ($expr:expr, $($arg: tt)*) => ({
        $crate::std::result::Result::Err(
            $crate::error::StrError::new(format!($($arg)*),
                                         $crate::std::option::Option::Some(
                                             $crate::std::boxed::Box::new($expr))))
    })
}

pub type StrResult<T> = Result<T, StrError>;

pub struct StrError {
    description: String,
    cause: Option<Box<Error>>
}

impl Display for StrError {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        try!(write!(f, "{}", self.description()));
        match self.cause() {
            None => Ok(()),
            Some(error) => {
                write!(f, ": {}", error)
            }
        }
    }
}

impl Debug for StrError {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        Display::fmt(self, f)
    }
}

impl Error for StrError {
    fn description(&self) -> &str {
        self.description.as_ref()
    }

    fn cause(&self) -> Option<&Error> {
        match self.cause {
            None => None,
            Some(ref error) => Some(error.borrow())
        }
    }
}

impl StrError {
    pub fn new<T: Into<String>>(description: T, cause: Option<Box<Error>>) -> StrError {
        StrError {
            description: description.into(),
            cause: cause
        }
    }
}
<|endoftext|>