<commit_before>#![crate_name = "mnemosyne"]
#![crate_type = "lib"]
#![feature(rustc_private)]

extern crate rustc;
extern crate combine;

pub mod position;
pub mod ast;

use rustc::lib::llvm;
use rustc::lib::llvm::{ ContextRef
                      , BuilderRef
                      , ModuleRef
                      , ValueRef
                  };

use position::Positional;

pub type IRResult = Result<ValueRef, Positional<String>>;

/// LLVM compilation context.
///
/// This is based rather loosely on MIT License code from
/// the [iron-kaleidoscope](https://github.com/jauhien/iron-kaleidoscope)
/// tutorial, and from [`librustc_trans`](https://github.com/rust-lang/rust/blob/master/src/librustc_trans/trans/mod.rs)
/// from the Rust compiler.
pub struct LLVMContext {
    pub llctx: ContextRef,
    pub llmod: ModuleRef
}

impl LLVMContext {
    pub fn new(module_name: &str) -> Self {
        unsafe {
            let name = module_name.to_c_str().as_ptr();
            let c = llvm::LLVMContextCreate();
            let m = llvm::LLVMModuleCreateWithNameInContext(c, name);
            LLVMContext { llctx: c, llmod: m }
        }
    }
}

impl Drop for LLVMContext {
    fn drop(&mut self) {
        unsafe {
            llvm::LLVMDisposeModule(self.llmod);
            llvm::LLVMContextDispose(self.llctx);
        }
    }
}
<commit_msg>Start on LLVM stuff<commit_after>#![crate_name = "mnemosyne"]
#![crate_type = "lib"]
#![feature(rustc_private)]
#![feature(cstr_memory)]

extern crate rustc;
extern crate combine;

pub mod position;
pub mod ast;

use std::ffi::CString;

use rustc::lib::llvm;
use rustc::lib::llvm::{ ContextRef
                      , ModuleRef
                      , ValueRef
                  };

use position::Positional;

pub type IRResult = Result<ValueRef, Positional<String>>;

/// Trait for an object that can be compiled to LLVM IR
pub trait ToIR {
    fn to_ir(&self) -> IRResult;
}

/// LLVM compilation context.
///
/// This is based rather loosely on MIT License code from
/// the [iron-kaleidoscope](https://github.com/jauhien/iron-kaleidoscope)
/// tutorial, and from [`librustc_trans`](https://github.com/rust-lang/rust/blob/master/src/librustc_trans/trans/mod.rs)
/// from the Rust compiler.
pub struct LLVMContext {
    pub llctx: ContextRef,
    pub llmod: ModuleRef
}

impl LLVMContext {
    pub fn new(module_name: &str) -> Self {
        let name = CString::new(module_name).unwrap();
        unsafe {
            let c = llvm::LLVMContextCreate();
            assert!(c.is_null() == false,
                "Could not create LLVM context, ContextRef was null.");
            let m = llvm::LLVMModuleCreateWithNameInContext(name.into_raw(), c);
            assert!(m.is_null() == false,
                "Could not create LLVM context, ModuleRef was null.");
            LLVMContext { llctx: c, llmod: m }
        }
    }
}

impl Drop for LLVMContext {
    fn drop(&mut self) {
        unsafe {
            llvm::LLVMDisposeModule(self.llmod);
            llvm::LLVMContextDispose(self.llctx);
        }
    }
}
<|endoftext|>


<commit_before>#![crate_type = "lib"]
#![deny(missing_debug_implementations, missing_copy_implementations,
        trivial_casts, trivial_numeric_casts, unsafe_code, unstable_features,
        unused_import_braces, unused_qualifications)]
#![warn(missing_docs)]

//! This is a base library for dealing with DICOM information and communication.
//!
//! Sorry, no example yet!
//!

#[macro_use]
extern crate lazy_static;
extern crate byteorder;
extern crate encoding;
#[macro_use]
extern crate quick_error;

pub mod attribute;
pub mod error;
pub mod parser;
pub mod transfer_syntax;
pub mod data_element;
pub mod meta;

mod util;
<commit_msg>Mark unused_qualifications as a warning<commit_after>#![crate_type = "lib"]
#![deny(missing_debug_implementations, missing_copy_implementations,
        trivial_casts, trivial_numeric_casts, unsafe_code, unstable_features,
        unused_import_braces)]
#![warn(missing_docs, unused_qualifications)]

//! This is a base library for dealing with DICOM information and communication.
//!
//! Sorry, no example yet!
//!

#[macro_use]
extern crate lazy_static;
extern crate byteorder;
extern crate encoding;
#[macro_use]
extern crate quick_error;

pub mod attribute;
pub mod error;
pub mod parser;
pub mod transfer_syntax;
pub mod data_element;
pub mod meta;

mod util;
<|endoftext|>


<commit_before>extern crate crossbeam;
extern crate clap;
#[macro_use] extern crate version;
#[macro_use] extern crate log;
extern crate walkdir;

extern crate libimagrt;
extern crate libimagerror;

use std::env;
use std::process::exit;
use std::process::Command;
use std::process::Stdio;
use std::io::ErrorKind;

use walkdir::WalkDir;
use crossbeam::*;
use clap::{Arg, AppSettings, SubCommand};

use libimagrt::runtime::Runtime;
use libimagerror::trace::trace_error;

/// Returns the helptext, putting the Strings in cmds as possible
/// subcommands into it
fn help_text(cmds: Vec<String>) -> String {
    let text = format!(r#"

     _
    (_)_ __ ___   __ _  __ _
    | | '_ \` _ \/ _\`|/ _\`|
    | | | | | | | (_| | (_| |
    |_|_| |_| |_|\__,_|\__, |
                       |___/
    -------------------------

    Usage: imag [--version | --versions | -h | --help] <command> <args...>

    imag - the personal information management suite for the commandline

    imag is a PIM suite for the commandline. It consists of several commands,
    called "modules". Each module implements one PIM aspect and all of these
    modules can be used independently.

    Available commands:

    {imagbins}

    Call a command with 'imag <command> <args>'
    Each command can be called with "--help" to get the respective helptext.

    Please visit https://github.com/matthiasbeyer/imag to view the source code,
    follow the development of imag or maybe even contribute to imag.

    imag is free software. It is released under the terms of LGPLv2.1

    (c) 2016 Matthias Beyer and contributors"#, imagbins = cmds.into_iter()
        .map(|cmd| format!("\t{}\n", cmd))
        .fold(String::new(), |s, c| {
            let s = s + c.as_str();
            s
        }));
    text
}

/// Returns the list of imag-* executables found in $PATH
fn get_commands() -> Vec<String> {
    let path = env::var("PATH");
    if path.is_err() {
        println!("PATH error: {:?}", path);
        exit(1);
    }
    let pathelements = path.unwrap();
    let pathelements = pathelements.split(":");

    let joinhandles : Vec<ScopedJoinHandle<Vec<String>>> = pathelements
        .map(|elem| {
            crossbeam::scope(|scope| {
                scope.spawn(|| {
                    WalkDir::new(elem)
                        .max_depth(1)
                        .into_iter()
                        .filter(|path| {
                            match path {
                                &Ok(ref p) => p.file_name()
                                    .to_str()
                                    .map_or(false, |filename| filename.starts_with("imag-")),
                                &Err(_)   => false,
                            }
                        })
                        .filter_map(|x| x.ok())
                        .filter_map(|path| {
                           path.file_name()
                               .to_str()
                               .and_then(|s| s.splitn(2, "-").nth(1).map(String::from))
                        })
                        .collect()
                })
            })
        })
        .collect();

    let mut execs = vec![];
    for joinhandle in joinhandles.into_iter() {
        let mut v = joinhandle.join();
        execs.append(&mut v);
    }

    execs
}

fn main() {
    // Initialize the Runtime and build the CLI
    let appname  = "imag";
    let version  = &version!();
    let about    = "imag - the PIM suite for the commandline";
    let commands = get_commands();
    let helptext = help_text(commands.clone());
    let app      = Runtime::get_default_cli_builder(appname, version, about)
        .settings(&[AppSettings::AllowExternalSubcommands, AppSettings::ArgRequiredElseHelp])
        .arg(Arg::with_name("version")
             .long("version")
             .takes_value(false)
             .required(false)
             .multiple(false)
             .help("Get the version of imag"))
        .arg(Arg::with_name("versions")
             .long("versions")
             .takes_value(false)
             .required(false)
             .multiple(false)
             .help("Get the versions of the imag commands"))
        .subcommand(SubCommand::with_name("help").help("Show help"))
        .help(helptext.as_str());
    let rt = Runtime::new(app)
        .unwrap_or_else(|e| {
            println!("Runtime couldn't be setup. Exiting");
            trace_error(&e);
            exit(1);
        });
    let matches = rt.cli();

    debug!("matches: {:?}", matches);

    // Begin checking for arguments

    if matches.is_present("version") {
        debug!("Showing version");
        println!("imag {}", &version!()[..]);
        exit(0);
    }

    if matches.is_present("versions") {
        debug!("Showing versions");
        let mut result = vec![];
        for command in get_commands().iter() {
            result.push(crossbeam::scope(|scope| {
                scope.spawn(|| {
                    let v = Command::new(format!("imag-{}",command)).arg("--version").output();
                    match v {
                        Ok(v) => match String::from_utf8(v.stdout) {
                            Ok(s) => format!("{:10} -> {}", command, s),
                            Err(e) => format!("Failed calling {} -> {:?}", command, e),
                        },
                        Err(e) => format!("Failed calling {} -> {:?}", command, e),
                    }
                })
            }))
        }

        for versionstring in result.into_iter().map(|handle| handle.join()) {
            // The amount of newlines may differ depending on the subprocess
            println!("{}", versionstring.trim());
        }
    }

    // Matches any subcommand given
    match matches.subcommand() {
        (subcommand, Some(scmd)) => {
            // Get all given arguments and further subcommands to pass to
            // the imag-<> binary
            // Providing no arguments is OK, and is therefore ignored here
            let subcommand_args : Vec<&str> = match scmd.values_of("") {
                Some(values) => values.collect(),
                None => Vec::new()
            };

            // Typos happen, so check if the given subcommand is one found in $PATH
            if !commands.clone().contains(&String::from(subcommand)) {
                println!("No such command: 'imag-{}'", subcommand);
                println!("See 'imag --help' for available subcommands");
                exit(2);
            }

            debug!("Calling 'imag-{}' with args: {:?}", subcommand, subcommand_args);

            // Create a Command, and pass it the gathered arguments
            match Command::new(format!("imag-{}", subcommand))
                .stdin(Stdio::inherit())
                .stdout(Stdio::inherit())
                .stderr(Stdio::inherit())
                .args(&subcommand_args[..])
                .spawn()
                .and_then(|mut handle| handle.wait())
            {
                Ok(exit_status) => {
                    if !exit_status.success() {
                        debug!("{} exited with non-zero exit code: {:?}", subcommand, exit_status);
                        println!("{} exited with non-zero exit code", subcommand);
                        exit(exit_status.code().unwrap_or(1));
                    }
                    debug!("Successful exit!");
                },

                Err(e) => {
                    debug!("Error calling the subcommand");
                    match e.kind() {
                        ErrorKind::NotFound => {
                            // With the check above, this absolutely should not happen.
                            // Keeping it to be safe
                            println!("No such command: 'imag-{}'", subcommand);
                            println!("See 'imag --help' for available subcommands");
                            exit(2);
                        },
                        ErrorKind::PermissionDenied => {
                            println!("No permission to execute: 'imag-{}'", subcommand);
                            exit(1);
                        },
                        _ => {
                            println!("Error spawning: {:?}", e);
                            exit(1);
                        }
                    }
                }
            }
        },
        // Calling for example 'imag --versions' will lead here, as this option does not exit.
        // There's nothing to do in such a case
        _ => {},
    }
}
<commit_msg>Reduce clone()-ing of commands to necessary places<commit_after>extern crate crossbeam;
extern crate clap;
#[macro_use] extern crate version;
#[macro_use] extern crate log;
extern crate walkdir;

extern crate libimagrt;
extern crate libimagerror;

use std::env;
use std::process::exit;
use std::process::Command;
use std::process::Stdio;
use std::io::ErrorKind;

use walkdir::WalkDir;
use crossbeam::*;
use clap::{Arg, AppSettings, SubCommand};

use libimagrt::runtime::Runtime;
use libimagerror::trace::trace_error;

/// Returns the helptext, putting the Strings in cmds as possible
/// subcommands into it
fn help_text(cmds: Vec<String>) -> String {
    let text = format!(r#"

     _
    (_)_ __ ___   __ _  __ _
    | | '_ \` _ \/ _\`|/ _\`|
    | | | | | | | (_| | (_| |
    |_|_| |_| |_|\__,_|\__, |
                       |___/
    -------------------------

    Usage: imag [--version | --versions | -h | --help] <command> <args...>

    imag - the personal information management suite for the commandline

    imag is a PIM suite for the commandline. It consists of several commands,
    called "modules". Each module implements one PIM aspect and all of these
    modules can be used independently.

    Available commands:

    {imagbins}

    Call a command with 'imag <command> <args>'
    Each command can be called with "--help" to get the respective helptext.

    Please visit https://github.com/matthiasbeyer/imag to view the source code,
    follow the development of imag or maybe even contribute to imag.

    imag is free software. It is released under the terms of LGPLv2.1

    (c) 2016 Matthias Beyer and contributors"#, imagbins = cmds.into_iter()
        .map(|cmd| format!("\t{}\n", cmd))
        .fold(String::new(), |s, c| {
            let s = s + c.as_str();
            s
        }));
    text
}

/// Returns the list of imag-* executables found in $PATH
fn get_commands() -> Vec<String> {
    let path = env::var("PATH");
    if path.is_err() {
        println!("PATH error: {:?}", path);
        exit(1);
    }
    let pathelements = path.unwrap();
    let pathelements = pathelements.split(":");

    let joinhandles : Vec<ScopedJoinHandle<Vec<String>>> = pathelements
        .map(|elem| {
            crossbeam::scope(|scope| {
                scope.spawn(|| {
                    WalkDir::new(elem)
                        .max_depth(1)
                        .into_iter()
                        .filter(|path| {
                            match path {
                                &Ok(ref p) => p.file_name()
                                    .to_str()
                                    .map_or(false, |filename| filename.starts_with("imag-")),
                                &Err(_)   => false,
                            }
                        })
                        .filter_map(|x| x.ok())
                        .filter_map(|path| {
                           path.file_name()
                               .to_str()
                               .and_then(|s| s.splitn(2, "-").nth(1).map(String::from))
                        })
                        .collect()
                })
            })
        })
        .collect();

    let mut execs = vec![];
    for joinhandle in joinhandles.into_iter() {
        let mut v = joinhandle.join();
        execs.append(&mut v);
    }

    execs
}

fn main() {
    // Initialize the Runtime and build the CLI
    let appname  = "imag";
    let version  = &version!();
    let about    = "imag - the PIM suite for the commandline";
    let commands = get_commands();
    let helptext = help_text(commands.clone());
    let app      = Runtime::get_default_cli_builder(appname, version, about)
        .settings(&[AppSettings::AllowExternalSubcommands, AppSettings::ArgRequiredElseHelp])
        .arg(Arg::with_name("version")
             .long("version")
             .takes_value(false)
             .required(false)
             .multiple(false)
             .help("Get the version of imag"))
        .arg(Arg::with_name("versions")
             .long("versions")
             .takes_value(false)
             .required(false)
             .multiple(false)
             .help("Get the versions of the imag commands"))
        .subcommand(SubCommand::with_name("help").help("Show help"))
        .help(helptext.as_str());
    let rt = Runtime::new(app)
        .unwrap_or_else(|e| {
            println!("Runtime couldn't be setup. Exiting");
            trace_error(&e);
            exit(1);
        });
    let matches = rt.cli();

    debug!("matches: {:?}", matches);

    // Begin checking for arguments

    if matches.is_present("version") {
        debug!("Showing version");
        println!("imag {}", &version!()[..]);
        exit(0);
    }

    if matches.is_present("versions") {
        debug!("Showing versions");
        let mut result = vec![];
        for command in commands.iter() {
            result.push(crossbeam::scope(|scope| {
                scope.spawn(|| {
                    let v = Command::new(format!("imag-{}",command)).arg("--version").output();
                    match v {
                        Ok(v) => match String::from_utf8(v.stdout) {
                            Ok(s) => format!("{:10} -> {}", command, s),
                            Err(e) => format!("Failed calling {} -> {:?}", command, e),
                        },
                        Err(e) => format!("Failed calling {} -> {:?}", command, e),
                    }
                })
            }))
        }

        for versionstring in result.into_iter().map(|handle| handle.join()) {
            // The amount of newlines may differ depending on the subprocess
            println!("{}", versionstring.trim());
        }
    }

    // Matches any subcommand given
    match matches.subcommand() {
        (subcommand, Some(scmd)) => {
            // Get all given arguments and further subcommands to pass to
            // the imag-<> binary
            // Providing no arguments is OK, and is therefore ignored here
            let subcommand_args : Vec<&str> = match scmd.values_of("") {
                Some(values) => values.collect(),
                None => Vec::new()
            };

            // Typos happen, so check if the given subcommand is one found in $PATH
            if !commands.contains(&String::from(subcommand)) {
                println!("No such command: 'imag-{}'", subcommand);
                println!("See 'imag --help' for available subcommands");
                exit(2);
            }

            debug!("Calling 'imag-{}' with args: {:?}", subcommand, subcommand_args);

            // Create a Command, and pass it the gathered arguments
            match Command::new(format!("imag-{}", subcommand))
                .stdin(Stdio::inherit())
                .stdout(Stdio::inherit())
                .stderr(Stdio::inherit())
                .args(&subcommand_args[..])
                .spawn()
                .and_then(|mut handle| handle.wait())
            {
                Ok(exit_status) => {
                    if !exit_status.success() {
                        debug!("{} exited with non-zero exit code: {:?}", subcommand, exit_status);
                        println!("{} exited with non-zero exit code", subcommand);
                        exit(exit_status.code().unwrap_or(1));
                    }
                    debug!("Successful exit!");
                },

                Err(e) => {
                    debug!("Error calling the subcommand");
                    match e.kind() {
                        ErrorKind::NotFound => {
                            // With the check above, this absolutely should not happen.
                            // Keeping it to be safe
                            println!("No such command: 'imag-{}'", subcommand);
                            println!("See 'imag --help' for available subcommands");
                            exit(2);
                        },
                        ErrorKind::PermissionDenied => {
                            println!("No permission to execute: 'imag-{}'", subcommand);
                            exit(1);
                        },
                        _ => {
                            println!("Error spawning: {:?}", e);
                            exit(1);
                        }
                    }
                }
            }
        },
        // Calling for example 'imag --versions' will lead here, as this option does not exit.
        // There's nothing to do in such a case
        _ => {},
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2020, The rav1e contributors. All rights reserved
//
// This source code is subject to the terms of the BSD 2 Clause License and
// the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
// was not distributed with this source code in the LICENSE file, you can
// obtain it at www.aomedia.org/license/software. If the Alliance for Open
// Media Patent License 1.0 was not distributed with this source code in the
// PATENTS file, you can obtain it at www.aomedia.org/license/patent.

use num_derive::*;

use crate::partition::BlockSize;
use crate::serialize::{Deserialize, Serialize};

use std::fmt;

// NOTE: Add Structures at the end.
/// Contains the speed settings.
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
pub struct SpeedSettings {
  /// Enables inter-frames to have multiple reference frames.
  ///
  /// Enabled is slower.
  pub multiref: bool,
  /// Enables fast deblocking filter.
  pub fast_deblock: bool,
  /// Enables reduced transform set.
  ///
  /// Enabled is faster.
  pub reduced_tx_set: bool,
  /// Enables using transform-domain distortion instead of pixel-domain.
  ///
  /// Enabled is faster.
  pub tx_domain_distortion: bool,
  /// Enables using transform-domain rate estimation.
  ///
  /// Enabled is faster.
  pub tx_domain_rate: bool,
  /// Enables bottom-up encoding, rather than top-down.
  ///
  /// Enabled is slower.
  pub encode_bottomup: bool,
  /// Enables searching transform size and type with RDO.
  ///
  /// Enabled is slower.
  pub rdo_tx_decision: bool,
  /// Prediction modes to search.
  ///
  /// Complex settings are slower.
  pub prediction_modes: PredictionModesSetting,
  /// Enables searching near motion vectors during RDO.
  ///
  /// Enabled is slower.
  pub include_near_mvs: bool,
  /// Disables scene-cut detection.
  ///
  /// Enabled is faster.
  pub no_scene_detection: bool,
  /// Fast scene detection mode, uses simple SAD instead of encoder cost estimates.
  pub fast_scene_detection: bool,
  /// Enables diamond motion vector search rather than full search.
  pub diamond_me: bool,
  /// Enables CDEF.
  pub cdef: bool,
  /// Enables LRF.
  pub lrf: bool,
  /// The amount of search done for self guided restoration.
  pub sgr_complexity: SGRComplexityLevel,
  /// Use SATD instead of SAD for subpixel search.
  ///
  /// Enabled is slower.
  pub use_satd_subpel: bool,
  /// Use non-square partition type everywhere
  ///
  /// Enabled is slower.
  pub non_square_partition: bool,

  /// Use segmentation.
  pub enable_segmentation: bool,

  /// Enable tx split for inter mode block.
  pub enable_inter_tx_split: bool,

  /// Use fine directional intra prediction
  pub fine_directional_intra: bool,

  // NOTE: put enums and basic type fields above
  /// Range of partition sizes that can be used. Larger ranges are slower.
  ///
  /// Must be based on square block sizes, so e.g. 8×4 isn't allowed here.
  pub partition_range: PartitionRange,
}

impl Default for SpeedSettings {
  /// This is currently used exclusively for feature testing and comparison.
  /// It is set to the slowest settings possible.
  fn default() -> Self {
    SpeedSettings {
      partition_range: PartitionRange::new(
        BlockSize::BLOCK_4X4,
        BlockSize::BLOCK_64X64,
      ),
      multiref: true,
      fast_deblock: false,
      reduced_tx_set: false,
      tx_domain_distortion: false,
      tx_domain_rate: false,
      encode_bottomup: true,
      rdo_tx_decision: true,
      prediction_modes: PredictionModesSetting::ComplexAll,
      include_near_mvs: true,
      no_scene_detection: false,
      fast_scene_detection: false,
      diamond_me: true,
      cdef: true,
      lrf: false,
      sgr_complexity: SGRComplexityLevel::Full,
      use_satd_subpel: true,
      non_square_partition: true,
      enable_segmentation: true,
      enable_inter_tx_split: false,
      fine_directional_intra: false,
    }
  }
}

impl SpeedSettings {
  /// Set the speed setting according to a numeric speed preset.
  ///
  /// The speed settings vary depending on speed value from 0 to 10.
  /// - 10 (fastest): min block size 64x64, reduced TX set, fast deblock, fast scenechange detection.
  /// - 9: min block size 32x32, reduced TX set, fast deblock.
  /// - 8: min block size 8x8, reduced TX set, fast deblock.
  /// - 7: min block size 8x8, reduced TX set.
  /// - 6 (default): min block size 8x8, reduced TX set, complex pred modes for keyframes.
  /// - 5: min block size 8x8, complex pred modes for keyframes, reduced TX set, RDO TX decision.
  /// - 4: min block size 8x8, complex pred modes for keyframes, RDO TX decision.
  /// - 3: min block size 8x8, complex pred modes for keyframes, RDO TX decision, include near MVs.
  /// - 2: min block size 4x4, complex pred modes, RDO TX decision, include near MVs.
  /// - 1: min block size 4x4, complex pred modes, RDO TX decision, include near MVs, bottom-up encoding.
  /// - 0 (slowest): min block size 4x4, complex pred modes, RDO TX decision, include near MVs, bottom-up encoding with non-square partitions everywhere
  pub fn from_preset(speed: usize) -> Self {
    SpeedSettings {
      partition_range: Self::partition_range_preset(speed),
      multiref: Self::multiref_preset(speed),
      fast_deblock: Self::fast_deblock_preset(speed),
      reduced_tx_set: Self::reduced_tx_set_preset(speed),
      tx_domain_distortion: Self::tx_domain_distortion_preset(speed),
      tx_domain_rate: Self::tx_domain_rate_preset(speed),
      encode_bottomup: Self::encode_bottomup_preset(speed),
      rdo_tx_decision: Self::rdo_tx_decision_preset(speed),
      prediction_modes: Self::prediction_modes_preset(speed),
      include_near_mvs: Self::include_near_mvs_preset(speed),
      no_scene_detection: Self::no_scene_detection_preset(speed),
      fast_scene_detection: Self::fast_scene_detection_preset(speed),
      diamond_me: Self::diamond_me_preset(speed),
      cdef: Self::cdef_preset(speed),
      lrf: Self::lrf_preset(speed),
      sgr_complexity: Self::sgr_complexity_preset(speed),
      use_satd_subpel: Self::use_satd_subpel(speed),
      non_square_partition: Self::non_square_partition_preset(speed),
      enable_segmentation: Self::enable_segmentation_preset(speed),
      enable_inter_tx_split: Self::enable_inter_tx_split_preset(speed),
      fine_directional_intra: Self::fine_directional_intra_preset(speed),
    }
  }

  /// This preset is set this way because 8x8 with reduced TX set is faster but with equivalent
  /// or better quality compared to 16x16 (to which reduced TX set does not apply).
  fn partition_range_preset(speed: usize) -> PartitionRange {
    if speed <= 2 {
      PartitionRange::new(BlockSize::BLOCK_4X4, BlockSize::BLOCK_64X64)
    } else if speed <= 8 {
      PartitionRange::new(BlockSize::BLOCK_8X8, BlockSize::BLOCK_64X64)
    } else if speed <= 9 {
      PartitionRange::new(BlockSize::BLOCK_32X32, BlockSize::BLOCK_64X64)
    } else {
      PartitionRange::new(BlockSize::BLOCK_32X32, BlockSize::BLOCK_32X32)
    }
  }

  /// Multiref is enabled automatically if low_latency is false.
  ///
  /// If low_latency is true, enabling multiref allows using multiple
  /// backwards references. low_latency false enables both forward and
  /// backwards references.
  const fn multiref_preset(speed: usize) -> bool {
    speed <= 7
  }

  const fn fast_deblock_preset(speed: usize) -> bool {
    speed >= 8
  }

  const fn reduced_tx_set_preset(speed: usize) -> bool {
    speed >= 5
  }

  /// TX domain distortion is always faster, with no significant quality change
  const fn tx_domain_distortion_preset(_speed: usize) -> bool {
    true
  }

  const fn tx_domain_rate_preset(_speed: usize) -> bool {
    false
  }

  const fn encode_bottomup_preset(speed: usize) -> bool {
    speed <= 1
  }

  const fn rdo_tx_decision_preset(speed: usize) -> bool {
    speed <= 5
  }

  fn prediction_modes_preset(speed: usize) -> PredictionModesSetting {
    if speed <= 2 {
      PredictionModesSetting::ComplexAll
    } else if speed <= 6 {
      PredictionModesSetting::ComplexKeyframes
    } else {
      PredictionModesSetting::Simple
    }
  }

  const fn include_near_mvs_preset(speed: usize) -> bool {
    speed <= 3
  }

  const fn no_scene_detection_preset(_speed: usize) -> bool {
    false
  }

  const fn fast_scene_detection_preset(speed: usize) -> bool {
    speed == 10
  }

  /// Currently Diamond ME gives better quality than full search on most videos,
  /// in addition to being faster.
  // There are a few outliers, such as the Wikipedia test clip.
  // TODO: Revisit this setting if full search quality improves in the future.
  const fn diamond_me_preset(_speed: usize) -> bool {
    true
  }

  const fn cdef_preset(_speed: usize) -> bool {
    true
  }

  const fn lrf_preset(speed: usize) -> bool {
    speed <= 9
  }

  fn sgr_complexity_preset(speed: usize) -> SGRComplexityLevel {
    if speed <= 8 {
      SGRComplexityLevel::Full
    } else {
      SGRComplexityLevel::Reduced
    }
  }

  const fn use_satd_subpel(speed: usize) -> bool {
    speed <= 9
  }

  const fn non_square_partition_preset(speed: usize) -> bool {
    speed == 0
  }

  // FIXME: this is currently only enabled at speed 0 because choosing a segment
  // requires doing RDO, but once that is replaced by a less bruteforce
  // solution we should be able to enable segmentation at all speeds.
  const fn enable_segmentation_preset(speed: usize) -> bool {
    speed == 0
  }

  // FIXME: With unknown reasons, inter_tx_split does not work if reduced_tx_set is false
  const fn enable_inter_tx_split_preset(speed: usize) -> bool {
    speed >= 9
  }

  fn fine_directional_intra_preset(speed: usize) -> bool {
    speed <= 1 || speed >= 6
  }
}

/// Range of block sizes to use.
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
pub struct PartitionRange {
  pub(crate) min: BlockSize,
  pub(crate) max: BlockSize,
}

impl PartitionRange {
  /// Creates a new partition range with min and max partition sizes.
  pub fn new(min: BlockSize, max: BlockSize) -> Self {
    assert!(max >= min);
    // Topdown search checks the min block size for PARTITION_SPLIT only, so
    // the min block size must be square.
    assert!(min.is_sqr());
    // Rectangular max partition sizes have not been tested.
    assert!(max.is_sqr());

    Self { min, max }
  }
}

/// Prediction modes to search.
#[derive(
  Clone,
  Copy,
  Debug,
  PartialOrd,
  PartialEq,
  FromPrimitive,
  Serialize,
  Deserialize,
)]
pub enum PredictionModesSetting {
  /// Only simple prediction modes.
  Simple,
  /// Search all prediction modes on key frames and simple modes on other
  /// frames.
  ComplexKeyframes,
  /// Search all prediction modes on all frames.
  ComplexAll,
}

impl fmt::Display for PredictionModesSetting {
  fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
    write!(
      f,
      "{}",
      match self {
        PredictionModesSetting::Simple => "Simple",
        PredictionModesSetting::ComplexKeyframes => "Complex-KFs",
        PredictionModesSetting::ComplexAll => "Complex-All",
      }
    )
  }
}

/// Search level for self guided restoration
#[derive(
  Clone,
  Copy,
  Debug,
  PartialOrd,
  PartialEq,
  FromPrimitive,
  Serialize,
  Deserialize,
)]
pub enum SGRComplexityLevel {
  /// Search all sgr parameters
  Full,
  /// Search a reduced set of sgr parameters
  Reduced,
}

impl fmt::Display for SGRComplexityLevel {
  fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
    write!(
      f,
      "{}",
      match self {
        SGRComplexityLevel::Full => "Full",
        SGRComplexityLevel::Reduced => "Reduced",
      }
    )
  }
}
<commit_msg>Enable fine directional intra prediction at speed 5<commit_after>// Copyright (c) 2020, The rav1e contributors. All rights reserved
//
// This source code is subject to the terms of the BSD 2 Clause License and
// the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
// was not distributed with this source code in the LICENSE file, you can
// obtain it at www.aomedia.org/license/software. If the Alliance for Open
// Media Patent License 1.0 was not distributed with this source code in the
// PATENTS file, you can obtain it at www.aomedia.org/license/patent.

use num_derive::*;

use crate::partition::BlockSize;
use crate::serialize::{Deserialize, Serialize};

use std::fmt;

// NOTE: Add Structures at the end.
/// Contains the speed settings.
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
pub struct SpeedSettings {
  /// Enables inter-frames to have multiple reference frames.
  ///
  /// Enabled is slower.
  pub multiref: bool,
  /// Enables fast deblocking filter.
  pub fast_deblock: bool,
  /// Enables reduced transform set.
  ///
  /// Enabled is faster.
  pub reduced_tx_set: bool,
  /// Enables using transform-domain distortion instead of pixel-domain.
  ///
  /// Enabled is faster.
  pub tx_domain_distortion: bool,
  /// Enables using transform-domain rate estimation.
  ///
  /// Enabled is faster.
  pub tx_domain_rate: bool,
  /// Enables bottom-up encoding, rather than top-down.
  ///
  /// Enabled is slower.
  pub encode_bottomup: bool,
  /// Enables searching transform size and type with RDO.
  ///
  /// Enabled is slower.
  pub rdo_tx_decision: bool,
  /// Prediction modes to search.
  ///
  /// Complex settings are slower.
  pub prediction_modes: PredictionModesSetting,
  /// Enables searching near motion vectors during RDO.
  ///
  /// Enabled is slower.
  pub include_near_mvs: bool,
  /// Disables scene-cut detection.
  ///
  /// Enabled is faster.
  pub no_scene_detection: bool,
  /// Fast scene detection mode, uses simple SAD instead of encoder cost estimates.
  pub fast_scene_detection: bool,
  /// Enables diamond motion vector search rather than full search.
  pub diamond_me: bool,
  /// Enables CDEF.
  pub cdef: bool,
  /// Enables LRF.
  pub lrf: bool,
  /// The amount of search done for self guided restoration.
  pub sgr_complexity: SGRComplexityLevel,
  /// Use SATD instead of SAD for subpixel search.
  ///
  /// Enabled is slower.
  pub use_satd_subpel: bool,
  /// Use non-square partition type everywhere
  ///
  /// Enabled is slower.
  pub non_square_partition: bool,

  /// Use segmentation.
  pub enable_segmentation: bool,

  /// Enable tx split for inter mode block.
  pub enable_inter_tx_split: bool,

  /// Use fine directional intra prediction
  pub fine_directional_intra: bool,

  // NOTE: put enums and basic type fields above
  /// Range of partition sizes that can be used. Larger ranges are slower.
  ///
  /// Must be based on square block sizes, so e.g. 8×4 isn't allowed here.
  pub partition_range: PartitionRange,
}

impl Default for SpeedSettings {
  /// This is currently used exclusively for feature testing and comparison.
  /// It is set to the slowest settings possible.
  fn default() -> Self {
    SpeedSettings {
      partition_range: PartitionRange::new(
        BlockSize::BLOCK_4X4,
        BlockSize::BLOCK_64X64,
      ),
      multiref: true,
      fast_deblock: false,
      reduced_tx_set: false,
      tx_domain_distortion: false,
      tx_domain_rate: false,
      encode_bottomup: true,
      rdo_tx_decision: true,
      prediction_modes: PredictionModesSetting::ComplexAll,
      include_near_mvs: true,
      no_scene_detection: false,
      fast_scene_detection: false,
      diamond_me: true,
      cdef: true,
      lrf: false,
      sgr_complexity: SGRComplexityLevel::Full,
      use_satd_subpel: true,
      non_square_partition: true,
      enable_segmentation: true,
      enable_inter_tx_split: false,
      fine_directional_intra: false,
    }
  }
}

impl SpeedSettings {
  /// Set the speed setting according to a numeric speed preset.
  ///
  /// The speed settings vary depending on speed value from 0 to 10.
  /// - 10 (fastest): min block size 64x64, reduced TX set, fast deblock, fast scenechange detection.
  /// - 9: min block size 32x32, reduced TX set, fast deblock.
  /// - 8: min block size 8x8, reduced TX set, fast deblock.
  /// - 7: min block size 8x8, reduced TX set.
  /// - 6 (default): min block size 8x8, reduced TX set, complex pred modes for keyframes.
  /// - 5: min block size 8x8, complex pred modes for keyframes, reduced TX set, RDO TX decision.
  /// - 4: min block size 8x8, complex pred modes for keyframes, RDO TX decision.
  /// - 3: min block size 8x8, complex pred modes for keyframes, RDO TX decision, include near MVs.
  /// - 2: min block size 4x4, complex pred modes, RDO TX decision, include near MVs.
  /// - 1: min block size 4x4, complex pred modes, RDO TX decision, include near MVs, bottom-up encoding.
  /// - 0 (slowest): min block size 4x4, complex pred modes, RDO TX decision, include near MVs, bottom-up encoding with non-square partitions everywhere
  pub fn from_preset(speed: usize) -> Self {
    SpeedSettings {
      partition_range: Self::partition_range_preset(speed),
      multiref: Self::multiref_preset(speed),
      fast_deblock: Self::fast_deblock_preset(speed),
      reduced_tx_set: Self::reduced_tx_set_preset(speed),
      tx_domain_distortion: Self::tx_domain_distortion_preset(speed),
      tx_domain_rate: Self::tx_domain_rate_preset(speed),
      encode_bottomup: Self::encode_bottomup_preset(speed),
      rdo_tx_decision: Self::rdo_tx_decision_preset(speed),
      prediction_modes: Self::prediction_modes_preset(speed),
      include_near_mvs: Self::include_near_mvs_preset(speed),
      no_scene_detection: Self::no_scene_detection_preset(speed),
      fast_scene_detection: Self::fast_scene_detection_preset(speed),
      diamond_me: Self::diamond_me_preset(speed),
      cdef: Self::cdef_preset(speed),
      lrf: Self::lrf_preset(speed),
      sgr_complexity: Self::sgr_complexity_preset(speed),
      use_satd_subpel: Self::use_satd_subpel(speed),
      non_square_partition: Self::non_square_partition_preset(speed),
      enable_segmentation: Self::enable_segmentation_preset(speed),
      enable_inter_tx_split: Self::enable_inter_tx_split_preset(speed),
      fine_directional_intra: Self::fine_directional_intra_preset(speed),
    }
  }

  /// This preset is set this way because 8x8 with reduced TX set is faster but with equivalent
  /// or better quality compared to 16x16 (to which reduced TX set does not apply).
  fn partition_range_preset(speed: usize) -> PartitionRange {
    if speed <= 2 {
      PartitionRange::new(BlockSize::BLOCK_4X4, BlockSize::BLOCK_64X64)
    } else if speed <= 8 {
      PartitionRange::new(BlockSize::BLOCK_8X8, BlockSize::BLOCK_64X64)
    } else if speed <= 9 {
      PartitionRange::new(BlockSize::BLOCK_32X32, BlockSize::BLOCK_64X64)
    } else {
      PartitionRange::new(BlockSize::BLOCK_32X32, BlockSize::BLOCK_32X32)
    }
  }

  /// Multiref is enabled automatically if low_latency is false.
  ///
  /// If low_latency is true, enabling multiref allows using multiple
  /// backwards references. low_latency false enables both forward and
  /// backwards references.
  const fn multiref_preset(speed: usize) -> bool {
    speed <= 7
  }

  const fn fast_deblock_preset(speed: usize) -> bool {
    speed >= 8
  }

  const fn reduced_tx_set_preset(speed: usize) -> bool {
    speed >= 5
  }

  /// TX domain distortion is always faster, with no significant quality change
  const fn tx_domain_distortion_preset(_speed: usize) -> bool {
    true
  }

  const fn tx_domain_rate_preset(_speed: usize) -> bool {
    false
  }

  const fn encode_bottomup_preset(speed: usize) -> bool {
    speed <= 1
  }

  const fn rdo_tx_decision_preset(speed: usize) -> bool {
    speed <= 5
  }

  fn prediction_modes_preset(speed: usize) -> PredictionModesSetting {
    if speed <= 2 {
      PredictionModesSetting::ComplexAll
    } else if speed <= 6 {
      PredictionModesSetting::ComplexKeyframes
    } else {
      PredictionModesSetting::Simple
    }
  }

  const fn include_near_mvs_preset(speed: usize) -> bool {
    speed <= 3
  }

  const fn no_scene_detection_preset(_speed: usize) -> bool {
    false
  }

  const fn fast_scene_detection_preset(speed: usize) -> bool {
    speed == 10
  }

  /// Currently Diamond ME gives better quality than full search on most videos,
  /// in addition to being faster.
  // There are a few outliers, such as the Wikipedia test clip.
  // TODO: Revisit this setting if full search quality improves in the future.
  const fn diamond_me_preset(_speed: usize) -> bool {
    true
  }

  const fn cdef_preset(_speed: usize) -> bool {
    true
  }

  const fn lrf_preset(speed: usize) -> bool {
    speed <= 9
  }

  fn sgr_complexity_preset(speed: usize) -> SGRComplexityLevel {
    if speed <= 8 {
      SGRComplexityLevel::Full
    } else {
      SGRComplexityLevel::Reduced
    }
  }

  const fn use_satd_subpel(speed: usize) -> bool {
    speed <= 9
  }

  const fn non_square_partition_preset(speed: usize) -> bool {
    speed == 0
  }

  // FIXME: this is currently only enabled at speed 0 because choosing a segment
  // requires doing RDO, but once that is replaced by a less bruteforce
  // solution we should be able to enable segmentation at all speeds.
  const fn enable_segmentation_preset(speed: usize) -> bool {
    speed == 0
  }

  // FIXME: With unknown reasons, inter_tx_split does not work if reduced_tx_set is false
  const fn enable_inter_tx_split_preset(speed: usize) -> bool {
    speed >= 9
  }

  fn fine_directional_intra_preset(speed: usize) -> bool {
    speed <= 1 || speed >= 5
  }
}

/// Range of block sizes to use.
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
pub struct PartitionRange {
  pub(crate) min: BlockSize,
  pub(crate) max: BlockSize,
}

impl PartitionRange {
  /// Creates a new partition range with min and max partition sizes.
  pub fn new(min: BlockSize, max: BlockSize) -> Self {
    assert!(max >= min);
    // Topdown search checks the min block size for PARTITION_SPLIT only, so
    // the min block size must be square.
    assert!(min.is_sqr());
    // Rectangular max partition sizes have not been tested.
    assert!(max.is_sqr());

    Self { min, max }
  }
}

/// Prediction modes to search.
#[derive(
  Clone,
  Copy,
  Debug,
  PartialOrd,
  PartialEq,
  FromPrimitive,
  Serialize,
  Deserialize,
)]
pub enum PredictionModesSetting {
  /// Only simple prediction modes.
  Simple,
  /// Search all prediction modes on key frames and simple modes on other
  /// frames.
  ComplexKeyframes,
  /// Search all prediction modes on all frames.
  ComplexAll,
}

impl fmt::Display for PredictionModesSetting {
  fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
    write!(
      f,
      "{}",
      match self {
        PredictionModesSetting::Simple => "Simple",
        PredictionModesSetting::ComplexKeyframes => "Complex-KFs",
        PredictionModesSetting::ComplexAll => "Complex-All",
      }
    )
  }
}

/// Search level for self guided restoration
#[derive(
  Clone,
  Copy,
  Debug,
  PartialOrd,
  PartialEq,
  FromPrimitive,
  Serialize,
  Deserialize,
)]
pub enum SGRComplexityLevel {
  /// Search all sgr parameters
  Full,
  /// Search a reduced set of sgr parameters
  Reduced,
}

impl fmt::Display for SGRComplexityLevel {
  fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
    write!(
      f,
      "{}",
      match self {
        SGRComplexityLevel::Full => "Full",
        SGRComplexityLevel::Reduced => "Reduced",
      }
    )
  }
}
<|endoftext|>


<commit_before>//! # The Redox OS Kernel, version 2
//!
//! The Redox OS Kernel is a hybrid kernel that supports X86_64 systems and
//! provides Unix-like syscalls for primarily Rust applications

#![feature(alloc)]
#![feature(arc_counts)]
#![feature(asm)]
#![feature(collections)]
#![feature(const_fn)]
#![feature(core_intrinsics)]
#![feature(drop_types_in_const)]
#![feature(heap_api)]
#![feature(integer_atomics)]
#![feature(never_type)]
#![feature(thread_local)]
#![no_std]

use arch::interrupt;

/// Architecture specific items (test)
#[cfg(test)]
#[macro_use]
extern crate arch_test as arch;

/// Architecture specific items (ARM)
#[cfg(all(not(test), target_arch = "arm"))]
#[macro_use]
extern crate arch_arm as arch;

/// Architecture specific items (x86_64)
#[cfg(all(not(test), target_arch = "x86_64"))]
#[macro_use]
extern crate arch_x86_64 as arch;

extern crate alloc;
#[macro_use]
extern crate collections;

#[macro_use]
extern crate bitflags;
extern crate goblin;
extern crate spin;

use core::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
use scheme::FileHandle;

#[macro_use]
#[macro_export]
/// Shared data structures
pub mod common;

/// Context management
pub mod context;

/// ELF file parsing
pub mod elf;

/// Schemes, filesystem handlers
pub mod scheme;

/// Synchronization primitives
pub mod sync;

/// Syscall handlers
pub mod syscall;

/// Tests
#[cfg(test)]
pub mod tests;

/// A unique number that identifies the current CPU - used for scheduling
#[thread_local]
static CPU_ID: AtomicUsize = ATOMIC_USIZE_INIT;

/// Get the current CPU's scheduling ID
#[inline(always)]
pub fn cpu_id() -> usize {
    CPU_ID.load(Ordering::Relaxed)
}

/// The count of all CPUs that can have work scheduled
static CPU_COUNT : AtomicUsize = ATOMIC_USIZE_INIT;

/// Get the number of CPUs currently active
#[inline(always)]
pub fn cpu_count() -> usize {
    CPU_COUNT.load(Ordering::Relaxed)
}

/// Initialize userspace by running the initfs:bin/init process
/// This function will also set the CWD to initfs:bin and open debug: as stdio
pub extern fn userspace_init() {
    assert_eq!(syscall::chdir(b"initfs:"), Ok(0));

    assert_eq!(syscall::open(b"debug:", syscall::flag::O_RDONLY).map(FileHandle::into), Ok(0));
    assert_eq!(syscall::open(b"debug:", syscall::flag::O_WRONLY).map(FileHandle::into), Ok(1));
    assert_eq!(syscall::open(b"debug:", syscall::flag::O_WRONLY).map(FileHandle::into), Ok(2));

    syscall::exec(b"initfs:/bin/init", &[]).expect("failed to execute initfs:init");

    panic!("initfs:init returned")
}

/// Allow exception handlers to send signal to arch-independant kernel
#[no_mangle]
pub extern fn ksignal(signal: usize) {
    println!("SIGNAL {}, CPU {}, PID {:?}", signal, cpu_id(), context::context_id());
    {
        let contexts = context::contexts();
        if let Some(context_lock) = contexts.current() {
            let context = context_lock.read();
            println!("NAME {}", unsafe { ::core::str::from_utf8_unchecked(&context.name.lock()) });
        }
    }
    syscall::exit(signal & 0x7F);
}

/// This is the kernel entry point for the primary CPU. The arch crate is responsible for calling this
#[no_mangle]
pub extern fn kmain(cpus: usize) {
    CPU_ID.store(0, Ordering::SeqCst);
    CPU_COUNT.store(cpus, Ordering::SeqCst);

    context::init();

    let pid = syscall::getpid();
    println!("BSP: {:?} {}", pid, cpus);

    match context::contexts_mut().spawn(userspace_init) {
        Ok(context_lock) => {
            let mut context = context_lock.write();
            context.status = context::Status::Runnable;
        },
        Err(err) => {
            panic!("failed to spawn userspace_init: {:?}", err);
        }
    }

    loop {
        unsafe {
            interrupt::disable();
            if context::switch() {
                interrupt::enable_and_nop();
            } else {
                // Enable interrupts, then halt CPU (to save power) until the next interrupt is actually fired.
                interrupt::enable_and_halt();
            }
        }
    }
}

/// This is the main kernel entry point for secondary CPUs
#[no_mangle]
pub extern fn kmain_ap(id: usize) {
    CPU_ID.store(id, Ordering::SeqCst);

    context::init();

    let pid = syscall::getpid();
    println!("AP {}: {:?}", id, pid);

    // Disable APs for now
    loop {
        unsafe { interrupt::enable_and_halt(); }
    }
/*
    loop {
        unsafe {
            interrupt::disable();
            if context::switch() {
                interrupt::enable_and_nop();
            } else {
                // Enable interrupts, then halt CPU (to save power) until the next interrupt is actually fired.
                interrupt::enable_and_halt();
            }
        }
    }
*/
}
<commit_msg>More path cleanup<commit_after>//! # The Redox OS Kernel, version 2
//!
//! The Redox OS Kernel is a hybrid kernel that supports X86_64 systems and
//! provides Unix-like syscalls for primarily Rust applications

#![feature(alloc)]
#![feature(arc_counts)]
#![feature(asm)]
#![feature(collections)]
#![feature(const_fn)]
#![feature(core_intrinsics)]
#![feature(drop_types_in_const)]
#![feature(heap_api)]
#![feature(integer_atomics)]
#![feature(never_type)]
#![feature(thread_local)]
#![no_std]

use arch::interrupt;

/// Architecture specific items (test)
#[cfg(test)]
#[macro_use]
extern crate arch_test as arch;

/// Architecture specific items (ARM)
#[cfg(all(not(test), target_arch = "arm"))]
#[macro_use]
extern crate arch_arm as arch;

/// Architecture specific items (x86_64)
#[cfg(all(not(test), target_arch = "x86_64"))]
#[macro_use]
extern crate arch_x86_64 as arch;

extern crate alloc;
#[macro_use]
extern crate collections;

#[macro_use]
extern crate bitflags;
extern crate goblin;
extern crate spin;

use core::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
use scheme::FileHandle;

#[macro_use]
#[macro_export]
/// Shared data structures
pub mod common;

/// Context management
pub mod context;

/// ELF file parsing
pub mod elf;

/// Schemes, filesystem handlers
pub mod scheme;

/// Synchronization primitives
pub mod sync;

/// Syscall handlers
pub mod syscall;

/// Tests
#[cfg(test)]
pub mod tests;

/// A unique number that identifies the current CPU - used for scheduling
#[thread_local]
static CPU_ID: AtomicUsize = ATOMIC_USIZE_INIT;

/// Get the current CPU's scheduling ID
#[inline(always)]
pub fn cpu_id() -> usize {
    CPU_ID.load(Ordering::Relaxed)
}

/// The count of all CPUs that can have work scheduled
static CPU_COUNT : AtomicUsize = ATOMIC_USIZE_INIT;

/// Get the number of CPUs currently active
#[inline(always)]
pub fn cpu_count() -> usize {
    CPU_COUNT.load(Ordering::Relaxed)
}

/// Initialize userspace by running the initfs:bin/init process
/// This function will also set the CWD to initfs:bin and open debug: as stdio
pub extern fn userspace_init() {
    assert_eq!(syscall::chdir(b"initfs:"), Ok(0));

    assert_eq!(syscall::open(b"debug:", syscall::flag::O_RDONLY).map(FileHandle::into), Ok(0));
    assert_eq!(syscall::open(b"debug:", syscall::flag::O_WRONLY).map(FileHandle::into), Ok(1));
    assert_eq!(syscall::open(b"debug:", syscall::flag::O_WRONLY).map(FileHandle::into), Ok(2));

    syscall::exec(b"/bin/init", &[]).expect("failed to execute init");

    panic!("init returned")
}

/// Allow exception handlers to send signal to arch-independant kernel
#[no_mangle]
pub extern fn ksignal(signal: usize) {
    println!("SIGNAL {}, CPU {}, PID {:?}", signal, cpu_id(), context::context_id());
    {
        let contexts = context::contexts();
        if let Some(context_lock) = contexts.current() {
            let context = context_lock.read();
            println!("NAME {}", unsafe { ::core::str::from_utf8_unchecked(&context.name.lock()) });
        }
    }
    syscall::exit(signal & 0x7F);
}

/// This is the kernel entry point for the primary CPU. The arch crate is responsible for calling this
#[no_mangle]
pub extern fn kmain(cpus: usize) {
    CPU_ID.store(0, Ordering::SeqCst);
    CPU_COUNT.store(cpus, Ordering::SeqCst);

    context::init();

    let pid = syscall::getpid();
    println!("BSP: {:?} {}", pid, cpus);

    match context::contexts_mut().spawn(userspace_init) {
        Ok(context_lock) => {
            let mut context = context_lock.write();
            context.status = context::Status::Runnable;
        },
        Err(err) => {
            panic!("failed to spawn userspace_init: {:?}", err);
        }
    }

    loop {
        unsafe {
            interrupt::disable();
            if context::switch() {
                interrupt::enable_and_nop();
            } else {
                // Enable interrupts, then halt CPU (to save power) until the next interrupt is actually fired.
                interrupt::enable_and_halt();
            }
        }
    }
}

/// This is the main kernel entry point for secondary CPUs
#[no_mangle]
pub extern fn kmain_ap(id: usize) {
    CPU_ID.store(id, Ordering::SeqCst);

    context::init();

    let pid = syscall::getpid();
    println!("AP {}: {:?}", id, pid);

    // Disable APs for now
    loop {
        unsafe { interrupt::enable_and_halt(); }
    }
/*
    loop {
        unsafe {
            interrupt::disable();
            if context::switch() {
                interrupt::enable_and_nop();
            } else {
                // Enable interrupts, then halt CPU (to save power) until the next interrupt is actually fired.
                interrupt::enable_and_halt();
            }
        }
    }
*/
}
<|endoftext|>


<commit_before>/* This file is part of Grust, GObject introspection bindings for Rust
 *
 * Copyright (C) 2013, 2014  Mikhail Zabaluev <mikhail.zabaluev@gmail.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301  USA
 */

use gtype::GType;
use ffi;
use ffi::GTypeInstance;
use refcount::RefcountFuncs;
use util::is_false;

use std::c_str::CString;
use std::mem::transmute;

pub trait ObjectType {
    fn get_type(&self) -> GType;
}

pub static refcount_funcs: RefcountFuncs = (
        &ffi::g_object_ref,
        &ffi::g_object_unref
    );

pub fn cast<'a, T: ObjectType, U: ObjectType>(source: &'a T)
                                             -> &'a U {
    unsafe {
        let inst = source as *const T as *const GTypeInstance;
        let dest: &'a U = transmute(source);
        let dest_type = dest.get_type();
        if is_false(ffi::g_type_check_instance_is_a(inst, dest_type)) {
            fail!("invalid cast to type {}",
                  CString::new(ffi::g_type_name(dest_type), false));
        }
        dest
    }
}
<commit_msg>Added object::cast_mut<commit_after>/* This file is part of Grust, GObject introspection bindings for Rust
 *
 * Copyright (C) 2013, 2014  Mikhail Zabaluev <mikhail.zabaluev@gmail.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301  USA
 */

use gtype::GType;
use ffi;
use ffi::GTypeInstance;
use refcount::RefcountFuncs;
use util::is_false;

use std::c_str::CString;
use std::mem::transmute;

pub trait ObjectType {
    fn get_type(&self) -> GType;
}

pub static refcount_funcs: RefcountFuncs = (
        &ffi::g_object_ref,
        &ffi::g_object_unref
    );

pub fn cast<'a, T: ObjectType, U: ObjectType>(source: &'a T)
                                             -> &'a U {
    unsafe {
        let inst = source as *const T as *const GTypeInstance;
        let dest: &'a U = transmute(source);
        let dest_type = dest.get_type();
        if is_false(ffi::g_type_check_instance_is_a(inst, dest_type)) {
            fail!("invalid cast to type {}",
                  CString::new(ffi::g_type_name(dest_type), false));
        }
        dest
    }
}

pub fn cast_mut<'a, T: ObjectType, U: ObjectType>(source: &'a mut T)
                                                  -> &'a mut U {
    unsafe {
        let inst = source as *mut T as *const T as *const GTypeInstance;
        let dest: &'a mut U = transmute(source);
        let dest_type = dest.get_type();
        if is_false(ffi::g_type_check_instance_is_a(inst, dest_type)) {
            fail!("invalid cast to type {}",
                  CString::new(ffi::g_type_name(dest_type), false));
        }
        dest
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use common::Diagnostic;
use graphql_ir::{
    FragmentDefinition, OperationDefinition, Program, ValidationMessage, ValidationResult,
    Validator,
};
use graphql_syntax::OperationKind;

mod extract_module_name;

pub fn validate_module_names(program: &Program) -> ValidationResult<()> {
    (ValidateModuleNames {}).validate_program(program)
}

pub struct ValidateModuleNames {}

impl Validator for ValidateModuleNames {
    const NAME: &'static str = "ValidateModuleNames";
    const VALIDATE_ARGUMENTS: bool = false;
    const VALIDATE_DIRECTIVES: bool = true;

    fn validate_operation(&mut self, operation: &OperationDefinition) -> ValidationResult<()> {
        let operation_name = operation.name.item.to_string();
        let path = operation.name.location.source_location().path();
        let module_name =
            extract_module_name::extract_module_name(path).expect("Unable to extract module name.");
        let (operation_type_suffix, pluralized_string) = match operation.kind {
            OperationKind::Query => ("Query", "Queries"),
            OperationKind::Mutation => ("Mutation", "Mutations"),
            OperationKind::Subscription => ("Subscription", "Subscriptions"),
        };

        if !operation_name.starts_with(&module_name)
        // TODO: T71484519 re-enable this line when queries are correctly named in www
        // || !operation_name.ends_with(operation_type_suffix)
        {
            return Err(vec![Diagnostic::error(
                ValidationMessage::InvalidOperationName {
                    pluralized_string: pluralized_string.to_string(),
                    operation_type_suffix: operation_type_suffix.to_string(),
                    module_name,
                    operation_name,
                },
                operation.name.location,
            )]);
        }

        Ok(())
    }

    fn validate_fragment(&mut self, fragment: &FragmentDefinition) -> ValidationResult<()> {
        let fragment_name = fragment.name.item.to_string();
        let path = fragment.name.location.source_location().path();
        let module_name =
            extract_module_name::extract_module_name(path).expect("Unable to extract module name.");

        if !fragment_name.starts_with(&module_name) {
            return Err(vec![Diagnostic::error(
                ValidationMessage::InvalidFragmentName {
                    module_name,
                    fragment_name,
                },
                fragment.name.location,
            )]);
        }
        Ok(())
    }
}
<commit_msg>Rust compiler: only check that an operation ends with Query or Subscription or Mutation<commit_after>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use common::Diagnostic;
use graphql_ir::{
    FragmentDefinition, OperationDefinition, Program, ValidationMessage, ValidationResult,
    Validator,
};
use graphql_syntax::OperationKind;

mod extract_module_name;

pub fn validate_module_names(program: &Program) -> ValidationResult<()> {
    (ValidateModuleNames {}).validate_program(program)
}

pub struct ValidateModuleNames {}

impl Validator for ValidateModuleNames {
    const NAME: &'static str = "ValidateModuleNames";
    const VALIDATE_ARGUMENTS: bool = false;
    const VALIDATE_DIRECTIVES: bool = true;

    fn validate_operation(&mut self, operation: &OperationDefinition) -> ValidationResult<()> {
        let operation_name = operation.name.item.to_string();
        let path = operation.name.location.source_location().path();
        let module_name =
            extract_module_name::extract_module_name(path).expect("Unable to extract module name.");
        let (operation_type_suffix, pluralized_string) = match operation.kind {
            OperationKind::Query => ("Query", "Queries"),
            OperationKind::Mutation => ("Mutation", "Mutations"),
            OperationKind::Subscription => ("Subscription", "Subscriptions"),
        };

        let operation_name_ending_is_valid = operation_name.ends_with("Query")
            || operation_name.ends_with("Mutation")
            || operation_name.ends_with("Subscription");

        if !operation_name.starts_with(&module_name) || !operation_name_ending_is_valid
        // TODO: T71484519 re-enable this line when queries are correctly named in www
        // || !operation_name.ends_with(operation_type_suffix)
        {
            return Err(vec![Diagnostic::error(
                ValidationMessage::InvalidOperationName {
                    pluralized_string: pluralized_string.to_string(),
                    operation_type_suffix: operation_type_suffix.to_string(),
                    module_name,
                    operation_name,
                },
                operation.name.location,
            )]);
        }

        Ok(())
    }

    fn validate_fragment(&mut self, fragment: &FragmentDefinition) -> ValidationResult<()> {
        let fragment_name = fragment.name.item.to_string();
        let path = fragment.name.location.source_location().path();
        let module_name =
            extract_module_name::extract_module_name(path).expect("Unable to extract module name.");

        if !fragment_name.starts_with(&module_name) {
            return Err(vec![Diagnostic::error(
                ValidationMessage::InvalidFragmentName {
                    module_name,
                    fragment_name,
                },
                fragment.name.location,
            )]);
        }
        Ok(())
    }
}
<|endoftext|>


<commit_before>// CITA
// Copyright 2016-2019 Cryptape Technologies LLC.

// This program is free software: you can redistribute it
// and/or modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any
// later version.

// This program is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

use crate::mq_agent::{MqAgentClient, PubMessage};
use crate::node_manager::{BroadcastReq, GetPeerCountReq, NodesManagerClient, SingleTxReq};
use crate::synchronizer::{SynchronizerClient, SynchronizerMessage};
use libproto::router::{MsgType, RoutingKey, SubModules};
use libproto::routing_key;
use libproto::snapshot::{Cmd, Resp, SnapshotResp};
use libproto::{Message as ProtoMessage, OperateType, Response};
use libproto::{TryFrom, TryInto};
use logger::{error, info, trace, warn};
use pubsub::channel::{unbounded, Receiver, Sender};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;

pub struct Network {
    is_pause: Arc<AtomicBool>,
    mq_client: MqAgentClient,
    network_client: NetworkClient,
    nodes_mgr_client: NodesManagerClient,
    sync_client: SynchronizerClient,
    msg_receiver: Receiver<NetworkMessage>,
}

impl Network {
    pub fn new(
        mq_client: MqAgentClient,
        nodes_mgr_client: NodesManagerClient,
        sync_client: SynchronizerClient,
    ) -> Self {
        let (tx, rx) = unbounded();
        let client = NetworkClient { sender: tx };
        Network {
            is_pause: Arc::new(AtomicBool::new(false)),
            mq_client,
            network_client: client,
            nodes_mgr_client,
            sync_client,
            msg_receiver: rx,
        }
    }

    pub fn client(&self) -> NetworkClient {
        self.network_client.clone()
    }

    pub fn run(&mut self) {
        loop {
            if let Ok(msg) = self.msg_receiver.recv() {
                msg.handle(self);
            }
        }
    }
}

#[derive(Clone, Debug)]
pub struct NetworkClient {
    sender: Sender<NetworkMessage>,
}

impl NetworkClient {
    pub fn new(sender: Sender<NetworkMessage>) -> Self {
        NetworkClient { sender }
    }

    pub fn handle_local_message(&self, msg: LocalMessage) {
        self.send_message(NetworkMessage::LocalMessage(msg));
    }

    pub fn handle_remote_message(&self, msg: RemoteMessage) {
        self.send_message(NetworkMessage::RemoteMessage(msg));
    }

    fn send_message(&self, msg: NetworkMessage) {
        self.sender.try_send(msg).unwrap_or_else(|err| {
            warn!("[Network] Send message to network failed : {:?}", err);
        });
    }
}

pub enum NetworkMessage {
    LocalMessage(LocalMessage),
    RemoteMessage(RemoteMessage),
}

impl NetworkMessage {
    pub fn handle(self, service: &mut Network) {
        match self {
            NetworkMessage::LocalMessage(msg) => msg.handle(service),
            NetworkMessage::RemoteMessage(msg) => msg.handle(service),
        }
    }
}
pub struct LocalMessage {
    key: String,
    data: Vec<u8>,
}

impl LocalMessage {
    pub fn new(key: String, data: Vec<u8>) -> Self {
        LocalMessage { key, data }
    }

    pub fn handle(self, service: &mut Network) {
        let rt_key = RoutingKey::from(&self.key);
        trace!("[Network] Receive Message from Local/{}", self.key);

        if service.is_pause.load(Ordering::SeqCst)
            && rt_key.get_sub_module() != SubModules::Snapshot
        {
            return;
        }

        match rt_key {
            routing_key!(Chain >> Status) => {
                service
                    .sync_client
                    .handle_local_status(SynchronizerMessage::new(self.key, self.data));
            }
            routing_key!(Chain >> SyncResponse) => {
                let msg = ProtoMessage::try_from(&self.data).unwrap();
                send_message(
                    &service.nodes_mgr_client,
                    routing_key!(Synchronizer >> SyncResponse).into(),
                    msg,
                );
            }
            routing_key!(Jsonrpc >> RequestNet) => {
                self.reply_rpc(&self.data, service);
            }
            routing_key!(Snapshot >> SnapshotReq) => {
                info!("[Network] Set disconnect and response");
                self.snapshot_req(&self.data, service);
            }
            _ => {
                error!("[Network] Unexpected key {} from Local", self.key);
            }
        }
    }

    fn reply_rpc(&self, data: &[u8], service: &mut Network) {
        let mut msg = ProtoMessage::try_from(data).unwrap();

        let req_opt = msg.take_request();
        {
            if let Some(mut req) = req_opt {
                // Get peer count and send back to JsonRpc from MQ
                if req.has_peercount() {
                    let mut response = Response::new();
                    response.set_request_id(req.take_request_id());

                    let (tx, rx) = unbounded();
                    service
                        .nodes_mgr_client
                        .get_peer_count(GetPeerCountReq::new(tx));

                    // Get peer count from rx channel
                    // FIXME: This is a block receive, double check about this
                    let peer_count = rx.recv().unwrap();
                    response.set_peercount(peer_count as u32);
                    let msg: ProtoMessage = response.into();
                    service.mq_client.send_peer_count(PubMessage::new(
                        routing_key!(Net >> Response).into(),
                        msg.try_into().unwrap(),
                    ));
                }
            } else {
                warn!("[Network] Receive unexpected rpc data");
            }
        }
    }

    fn snapshot_req(&self, data: &[u8], service: &mut Network) {
        let mut msg = ProtoMessage::try_from(data).unwrap();
        let req = msg.take_snapshot_req().unwrap();
        let mut resp = SnapshotResp::new();

        match req.cmd {
            Cmd::Snapshot => {
                info!("[Network] Snapshot receive cmd::Snapshot: {:?}", req);
                resp.set_resp(Resp::SnapshotAck);
                resp.set_flag(true);
            }
            Cmd::Begin => {
                info!("[Network] Snapshot receive cmd::Begin: {:?}", req);
                service.is_pause.store(true, Ordering::SeqCst);
                resp.set_resp(Resp::BeginAck);
                resp.set_flag(true);
            }
            Cmd::Restore => {
                info!("[Network] Snapshot receive cmd::Restore: {:?}", req);
                resp.set_resp(Resp::RestoreAck);
                resp.set_flag(true);
            }
            Cmd::Clear => {
                info!("[Network] Snapshot receive cmd::Clear: {:?}", req);
                resp.set_resp(Resp::ClearAck);
                resp.set_flag(true);
            }
            Cmd::End => {
                info!("[Network] Snapshot receive cmd::End: {:?}", req);
                service.is_pause.store(false, Ordering::SeqCst);
                resp.set_resp(Resp::EndAck);
                resp.set_flag(true);
            }
        }

        let msg: ProtoMessage = resp.into();
        service.mq_client.send_snapshot_resp(PubMessage::new(
            routing_key!(Net >> SnapshotResp).into(),
            (&msg).try_into().unwrap(),
        ));
    }
}

pub struct RemoteMessage {
    key: String,
    data: Vec<u8>,
}

impl RemoteMessage {
    pub fn new(key: String, data: Vec<u8>) -> Self {
        RemoteMessage { key, data }
    }

    pub fn handle(self, service: &mut Network) {
        let rt_key = RoutingKey::from(&self.key);
        trace!("[Network] Receive Message from Remote/{}", self.key);

        if service.is_pause.load(Ordering::SeqCst)
            && rt_key.get_sub_module() != SubModules::Snapshot
        {
            return;
        }

        match rt_key {
            routing_key!(Synchronizer >> Status) => {
                service
                    .sync_client
                    .handle_remote_status(SynchronizerMessage::new(self.key, self.data));
            }
            routing_key!(Synchronizer >> SyncResponse) => {
                service
                    .sync_client
                    .handle_remote_response(SynchronizerMessage::new(self.key, self.data));
            }
            routing_key!(Synchronizer >> SyncRequest) => {
                service.mq_client.pub_sync_request(PubMessage::new(
                    routing_key!(Net >> SyncRequest).into(),
                    self.data,
                ));
            }
            routing_key!(Consensus >> CompactSignedProposal) => {
                let msg =
                    PubMessage::new(routing_key!(Net >> CompactSignedProposal).into(), self.data);
                service.mq_client.forward_msg_to_consensus(msg);
            }
            routing_key!(Consensus >> RawBytes) => {
                let msg = PubMessage::new(routing_key!(Net >> RawBytes).into(), self.data);
                service.mq_client.forward_msg_to_consensus(msg);
            }
            routing_key!(Auth >> Request) => {
                let msg = PubMessage::new(routing_key!(Net >> Request).into(), self.data);
                service.mq_client.forward_msg_to_auth(msg);
            }
            routing_key!(Auth >> GetBlockTxn) => {
                let msg = PubMessage::new(routing_key!(Net >> GetBlockTxn).into(), self.data);
                service.mq_client.forward_msg_to_auth(msg);
            }
            routing_key!(Auth >> BlockTxn) => {
                let msg = PubMessage::new(routing_key!(Net >> BlockTxn).into(), self.data);
                service.mq_client.forward_msg_to_auth(msg);
            }
            _ => {
                error!("[Network] Unexpected key {} from Remote", self.key);
            }
        }
    }
}

pub fn send_message(nodes_mgr_client: &NodesManagerClient, key: String, msg: ProtoMessage) {
    let operate = msg.get_operate();

    match operate {
        OperateType::Broadcast => {
            nodes_mgr_client.broadcast(BroadcastReq::new(key, msg));
        }
        OperateType::Single => {
            let dst = msg.get_origin();
            nodes_mgr_client.send_message(SingleTxReq::new(dst as usize, key, msg));
        }
        OperateType::Subtract => {
            // FIXME: Support subtract broadcast if necessary.
            warn!("[MqAgent] Subtract broadcast does not support yet!");
        }
    }
}
<commit_msg>Use broadcast for subtract broadcast<commit_after>// CITA
// Copyright 2016-2019 Cryptape Technologies LLC.

// This program is free software: you can redistribute it
// and/or modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any
// later version.

// This program is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

use crate::mq_agent::{MqAgentClient, PubMessage};
use crate::node_manager::{BroadcastReq, GetPeerCountReq, NodesManagerClient, SingleTxReq};
use crate::synchronizer::{SynchronizerClient, SynchronizerMessage};
use libproto::router::{MsgType, RoutingKey, SubModules};
use libproto::routing_key;
use libproto::snapshot::{Cmd, Resp, SnapshotResp};
use libproto::{Message as ProtoMessage, OperateType, Response};
use libproto::{TryFrom, TryInto};
use logger::{error, info, trace, warn};
use pubsub::channel::{unbounded, Receiver, Sender};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;

pub struct Network {
    is_pause: Arc<AtomicBool>,
    mq_client: MqAgentClient,
    network_client: NetworkClient,
    nodes_mgr_client: NodesManagerClient,
    sync_client: SynchronizerClient,
    msg_receiver: Receiver<NetworkMessage>,
}

impl Network {
    pub fn new(
        mq_client: MqAgentClient,
        nodes_mgr_client: NodesManagerClient,
        sync_client: SynchronizerClient,
    ) -> Self {
        let (tx, rx) = unbounded();
        let client = NetworkClient { sender: tx };
        Network {
            is_pause: Arc::new(AtomicBool::new(false)),
            mq_client,
            network_client: client,
            nodes_mgr_client,
            sync_client,
            msg_receiver: rx,
        }
    }

    pub fn client(&self) -> NetworkClient {
        self.network_client.clone()
    }

    pub fn run(&mut self) {
        loop {
            if let Ok(msg) = self.msg_receiver.recv() {
                msg.handle(self);
            }
        }
    }
}

#[derive(Clone, Debug)]
pub struct NetworkClient {
    sender: Sender<NetworkMessage>,
}

impl NetworkClient {
    pub fn new(sender: Sender<NetworkMessage>) -> Self {
        NetworkClient { sender }
    }

    pub fn handle_local_message(&self, msg: LocalMessage) {
        self.send_message(NetworkMessage::LocalMessage(msg));
    }

    pub fn handle_remote_message(&self, msg: RemoteMessage) {
        self.send_message(NetworkMessage::RemoteMessage(msg));
    }

    fn send_message(&self, msg: NetworkMessage) {
        self.sender.try_send(msg).unwrap_or_else(|err| {
            warn!("[Network] Send message to network failed : {:?}", err);
        });
    }
}

pub enum NetworkMessage {
    LocalMessage(LocalMessage),
    RemoteMessage(RemoteMessage),
}

impl NetworkMessage {
    pub fn handle(self, service: &mut Network) {
        match self {
            NetworkMessage::LocalMessage(msg) => msg.handle(service),
            NetworkMessage::RemoteMessage(msg) => msg.handle(service),
        }
    }
}
pub struct LocalMessage {
    key: String,
    data: Vec<u8>,
}

impl LocalMessage {
    pub fn new(key: String, data: Vec<u8>) -> Self {
        LocalMessage { key, data }
    }

    pub fn handle(self, service: &mut Network) {
        let rt_key = RoutingKey::from(&self.key);
        trace!("[Network] Receive Message from Local/{}", self.key);

        if service.is_pause.load(Ordering::SeqCst)
            && rt_key.get_sub_module() != SubModules::Snapshot
        {
            return;
        }

        match rt_key {
            routing_key!(Chain >> Status) => {
                service
                    .sync_client
                    .handle_local_status(SynchronizerMessage::new(self.key, self.data));
            }
            routing_key!(Chain >> SyncResponse) => {
                let msg = ProtoMessage::try_from(&self.data).unwrap();
                send_message(
                    &service.nodes_mgr_client,
                    routing_key!(Synchronizer >> SyncResponse).into(),
                    msg,
                );
            }
            routing_key!(Jsonrpc >> RequestNet) => {
                self.reply_rpc(&self.data, service);
            }
            routing_key!(Snapshot >> SnapshotReq) => {
                info!("[Network] Set disconnect and response");
                self.snapshot_req(&self.data, service);
            }
            _ => {
                error!("[Network] Unexpected key {} from Local", self.key);
            }
        }
    }

    fn reply_rpc(&self, data: &[u8], service: &mut Network) {
        let mut msg = ProtoMessage::try_from(data).unwrap();

        let req_opt = msg.take_request();
        {
            if let Some(mut req) = req_opt {
                // Get peer count and send back to JsonRpc from MQ
                if req.has_peercount() {
                    let mut response = Response::new();
                    response.set_request_id(req.take_request_id());

                    let (tx, rx) = unbounded();
                    service
                        .nodes_mgr_client
                        .get_peer_count(GetPeerCountReq::new(tx));

                    // Get peer count from rx channel
                    // FIXME: This is a block receive, double check about this
                    let peer_count = rx.recv().unwrap();
                    response.set_peercount(peer_count as u32);
                    let msg: ProtoMessage = response.into();
                    service.mq_client.send_peer_count(PubMessage::new(
                        routing_key!(Net >> Response).into(),
                        msg.try_into().unwrap(),
                    ));
                }
            } else {
                warn!("[Network] Receive unexpected rpc data");
            }
        }
    }

    fn snapshot_req(&self, data: &[u8], service: &mut Network) {
        let mut msg = ProtoMessage::try_from(data).unwrap();
        let req = msg.take_snapshot_req().unwrap();
        let mut resp = SnapshotResp::new();

        match req.cmd {
            Cmd::Snapshot => {
                info!("[Network] Snapshot receive cmd::Snapshot: {:?}", req);
                resp.set_resp(Resp::SnapshotAck);
                resp.set_flag(true);
            }
            Cmd::Begin => {
                info!("[Network] Snapshot receive cmd::Begin: {:?}", req);
                service.is_pause.store(true, Ordering::SeqCst);
                resp.set_resp(Resp::BeginAck);
                resp.set_flag(true);
            }
            Cmd::Restore => {
                info!("[Network] Snapshot receive cmd::Restore: {:?}", req);
                resp.set_resp(Resp::RestoreAck);
                resp.set_flag(true);
            }
            Cmd::Clear => {
                info!("[Network] Snapshot receive cmd::Clear: {:?}", req);
                resp.set_resp(Resp::ClearAck);
                resp.set_flag(true);
            }
            Cmd::End => {
                info!("[Network] Snapshot receive cmd::End: {:?}", req);
                service.is_pause.store(false, Ordering::SeqCst);
                resp.set_resp(Resp::EndAck);
                resp.set_flag(true);
            }
        }

        let msg: ProtoMessage = resp.into();
        service.mq_client.send_snapshot_resp(PubMessage::new(
            routing_key!(Net >> SnapshotResp).into(),
            (&msg).try_into().unwrap(),
        ));
    }
}

pub struct RemoteMessage {
    key: String,
    data: Vec<u8>,
}

impl RemoteMessage {
    pub fn new(key: String, data: Vec<u8>) -> Self {
        RemoteMessage { key, data }
    }

    pub fn handle(self, service: &mut Network) {
        let rt_key = RoutingKey::from(&self.key);
        trace!("[Network] Receive Message from Remote/{}", self.key);

        if service.is_pause.load(Ordering::SeqCst)
            && rt_key.get_sub_module() != SubModules::Snapshot
        {
            return;
        }

        match rt_key {
            routing_key!(Synchronizer >> Status) => {
                service
                    .sync_client
                    .handle_remote_status(SynchronizerMessage::new(self.key, self.data));
            }
            routing_key!(Synchronizer >> SyncResponse) => {
                service
                    .sync_client
                    .handle_remote_response(SynchronizerMessage::new(self.key, self.data));
            }
            routing_key!(Synchronizer >> SyncRequest) => {
                service.mq_client.pub_sync_request(PubMessage::new(
                    routing_key!(Net >> SyncRequest).into(),
                    self.data,
                ));
            }
            routing_key!(Consensus >> CompactSignedProposal) => {
                let msg =
                    PubMessage::new(routing_key!(Net >> CompactSignedProposal).into(), self.data);
                service.mq_client.forward_msg_to_consensus(msg);
            }
            routing_key!(Consensus >> RawBytes) => {
                let msg = PubMessage::new(routing_key!(Net >> RawBytes).into(), self.data);
                service.mq_client.forward_msg_to_consensus(msg);
            }
            routing_key!(Auth >> Request) => {
                let msg = PubMessage::new(routing_key!(Net >> Request).into(), self.data);
                service.mq_client.forward_msg_to_auth(msg);
            }
            routing_key!(Auth >> GetBlockTxn) => {
                let msg = PubMessage::new(routing_key!(Net >> GetBlockTxn).into(), self.data);
                service.mq_client.forward_msg_to_auth(msg);
            }
            routing_key!(Auth >> BlockTxn) => {
                let msg = PubMessage::new(routing_key!(Net >> BlockTxn).into(), self.data);
                service.mq_client.forward_msg_to_auth(msg);
            }
            _ => {
                error!("[Network] Unexpected key {} from Remote", self.key);
            }
        }
    }
}

pub fn send_message(nodes_mgr_client: &NodesManagerClient, key: String, msg: ProtoMessage) {
    let operate = msg.get_operate();

    match operate {
        OperateType::Broadcast => {
            nodes_mgr_client.broadcast(BroadcastReq::new(key, msg));
        }
        OperateType::Single => {
            let dst = msg.get_origin();
            nodes_mgr_client.send_message(SingleTxReq::new(dst as usize, key, msg));
        }
        OperateType::Subtract => {
            // FIXME: Support subtract broadcast if necessary, just use broadcast instead.
            warn!("[MqAgent] Subtract broadcast does not support yet, use broadcast instead!");
            nodes_mgr_client.broadcast(BroadcastReq::new(key, msg));
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2018 Developers of the Rand project.
// Copyright 2013-2015 The Rust Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "windows")))]
pub fn get_nstime() -> u64 {
    use std::time::{SystemTime, UNIX_EPOCH};

    let dur = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
    // The correct way to calculate the current time is
    // `dur.as_secs() * 1_000_000_000 + dur.subsec_nanos() as u64`
    // But this is faster, and the difference in terms of entropy is
    // negligible (log2(10^9) == 29.9).
    dur.as_secs() << 30 | dur.subsec_nanos() as u64
}

#[cfg(any(target_os = "macos", target_os = "ios"))]
pub fn get_nstime() -> u64 {
    // On Mac OS and iOS std::time::SystemTime only has 1000ns resolution.
    // We use `mach_absolute_time` instead. This provides a CPU dependent
    // unit, to get real nanoseconds the result should by multiplied by
    // numer/denom from `mach_timebase_info`.
    // But we are not interested in the exact nanoseconds, just entropy. So
    // we use the raw result.
    unsafe { libc::mach_absolute_time() }
}

#[cfg(target_os = "windows")]
pub fn get_nstime() -> u64 {
    unsafe {
        let mut t = super::mem::zeroed();
        winapi::um::profileapi::QueryPerformanceCounter(&mut t);
        *t.QuadPart() as u64
    }
}
<commit_msg>Fix rand_jitter on older versions of rust<commit_after>// Copyright 2018 Developers of the Rand project.
// Copyright 2013-2015 The Rust Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "windows")))]
pub fn get_nstime() -> u64 {
    use std::time::{SystemTime, UNIX_EPOCH};

    let dur = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
    // The correct way to calculate the current time is
    // `dur.as_secs() * 1_000_000_000 + dur.subsec_nanos() as u64`
    // But this is faster, and the difference in terms of entropy is
    // negligible (log2(10^9) == 29.9).
    dur.as_secs() << 30 | dur.subsec_nanos() as u64
}

#[cfg(any(target_os = "macos", target_os = "ios"))]
pub fn get_nstime() -> u64 {
    use libc;

    // On Mac OS and iOS std::time::SystemTime only has 1000ns resolution.
    // We use `mach_absolute_time` instead. This provides a CPU dependent
    // unit, to get real nanoseconds the result should by multiplied by
    // numer/denom from `mach_timebase_info`.
    // But we are not interested in the exact nanoseconds, just entropy. So
    // we use the raw result.
    unsafe { libc::mach_absolute_time() }
}

#[cfg(target_os = "windows")]
pub fn get_nstime() -> u64 {
    unsafe {
        let mut t = super::mem::zeroed();
        winapi::um::profileapi::QueryPerformanceCounter(&mut t);
        *t.QuadPart() as u64
    }
}
<|endoftext|>