<commit_before>use std::env;
use std::fs::{self, File};
use std::io::Read;
use std::path::{Path, PathBuf};

use toml;

pub fn get_template_source(tpl_path: &Path) -> String {
    let mut f = match File::open(tpl_path) {
        Err(_) => panic!("unable to open template file '{}'", tpl_path.to_str().unwrap()),
        Ok(f) => f,
    };

    let mut s = String::new();
    f.read_to_string(&mut s).unwrap();
    if s.ends_with('\n') {
        let _ = s.pop();
    }
    s
}

pub fn find_template_from_path(path: &str, start_at: Option<&Path>) -> PathBuf {
    if let Some(root) = start_at {
        let relative = root.with_file_name(path);
        if relative.exists() {
            return relative.to_owned();
        }
    }

    let config = Config::from_file();
    for dir in &config.dirs {
        let rooted = dir.join(path);
        if rooted.exists() {
            return rooted;
        }
    }

    panic!("template {:?} not found in directories {:?}", path, config.dirs)
}

pub fn template_dirs() -> Vec<PathBuf> {
    Config::from_file().dirs
}

struct Config {
    dirs: Vec<PathBuf>,
}

impl Config {
    fn from_file() -> Config {
        let root = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
        let filename = root.join(CONFIG_FILE_NAME);

        let default = vec![root.join("templates")];
        let dirs = if filename.exists() {
            let config_str = fs::read_to_string(&filename)
                .expect(&format!("unable to read {}", filename.to_str().unwrap()));
            let raw: RawConfig = toml::from_str(&config_str)
                .expect(&format!("invalid TOML in {}", filename.to_str().unwrap()));
            raw.dirs
                .map(|dirs| dirs.into_iter().map(|dir| root.join(dir)).collect())
                .unwrap_or_else(|| default)
        } else {
            default
        };

        Config { dirs }
    }
}

#[derive(Deserialize)]
struct RawConfig {
    dirs: Option<Vec<String>>,
}

static CONFIG_FILE_NAME: &str = "askama.toml";

#[cfg(test)]
mod tests {
    use super::{find_template_from_path, get_template_source};

    #[test]
    fn get_source() {
        let path = find_template_from_path("sub/b.html", None);
        assert_eq!(get_template_source(&path), "bar");
    }

    #[test]
    fn find_absolute() {
        let root = find_template_from_path("a.html", None);
        let path = find_template_from_path("sub/b.html", Some(&root));
        assert!(path.to_str().unwrap().ends_with("sub/b.html"));
    }

    #[test]
    #[should_panic]
    fn find_relative_nonexistent() {
        let root = find_template_from_path("a.html", None);
        find_template_from_path("b.html", Some(&root));
    }

    #[test]
    fn find_relative() {
        let root = find_template_from_path("sub/b.html", None);
        let path = find_template_from_path("c.html", Some(&root));
        assert!(path.to_str().unwrap().ends_with("sub/c.html"));
    }

    #[test]
    fn find_relative_sub() {
        let root = find_template_from_path("sub/b.html", None);
        let path = find_template_from_path("sub1/d.html", Some(&root));
        assert!(path.to_str().unwrap().ends_with("sub/sub1/d.html"));
    }
}
<commit_msg>Rename Config::from_file() to Config::new()<commit_after>use std::env;
use std::fs::{self, File};
use std::io::Read;
use std::path::{Path, PathBuf};

use toml;

pub fn get_template_source(tpl_path: &Path) -> String {
    let mut f = match File::open(tpl_path) {
        Err(_) => panic!("unable to open template file '{}'", tpl_path.to_str().unwrap()),
        Ok(f) => f,
    };

    let mut s = String::new();
    f.read_to_string(&mut s).unwrap();
    if s.ends_with('\n') {
        let _ = s.pop();
    }
    s
}

pub fn find_template_from_path(path: &str, start_at: Option<&Path>) -> PathBuf {
    if let Some(root) = start_at {
        let relative = root.with_file_name(path);
        if relative.exists() {
            return relative.to_owned();
        }
    }

    let config = Config::new();
    for dir in &config.dirs {
        let rooted = dir.join(path);
        if rooted.exists() {
            return rooted;
        }
    }

    panic!("template {:?} not found in directories {:?}", path, config.dirs)
}

pub fn template_dirs() -> Vec<PathBuf> {
    Config::new().dirs
}

struct Config {
    dirs: Vec<PathBuf>,
}

impl Config {
    fn new() -> Config {
        let root = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
        let filename = root.join(CONFIG_FILE_NAME);

        let default = vec![root.join("templates")];
        let dirs = if filename.exists() {
            let config_str = fs::read_to_string(&filename)
                .expect(&format!("unable to read {}", filename.to_str().unwrap()));
            let raw: RawConfig = toml::from_str(&config_str)
                .expect(&format!("invalid TOML in {}", filename.to_str().unwrap()));
            raw.dirs
                .map(|dirs| dirs.into_iter().map(|dir| root.join(dir)).collect())
                .unwrap_or_else(|| default)
        } else {
            default
        };

        Config { dirs }
    }
}

#[derive(Deserialize)]
struct RawConfig {
    dirs: Option<Vec<String>>,
}

static CONFIG_FILE_NAME: &str = "askama.toml";

#[cfg(test)]
mod tests {
    use super::{find_template_from_path, get_template_source};

    #[test]
    fn get_source() {
        let path = find_template_from_path("sub/b.html", None);
        assert_eq!(get_template_source(&path), "bar");
    }

    #[test]
    fn find_absolute() {
        let root = find_template_from_path("a.html", None);
        let path = find_template_from_path("sub/b.html", Some(&root));
        assert!(path.to_str().unwrap().ends_with("sub/b.html"));
    }

    #[test]
    #[should_panic]
    fn find_relative_nonexistent() {
        let root = find_template_from_path("a.html", None);
        find_template_from_path("b.html", Some(&root));
    }

    #[test]
    fn find_relative() {
        let root = find_template_from_path("sub/b.html", None);
        let path = find_template_from_path("c.html", Some(&root));
        assert!(path.to_str().unwrap().ends_with("sub/c.html"));
    }

    #[test]
    fn find_relative_sub() {
        let root = find_template_from_path("sub/b.html", None);
        let path = find_template_from_path("sub1/d.html", Some(&root));
        assert!(path.to_str().unwrap().ends_with("sub/sub1/d.html"));
    }
}
<|endoftext|>


<commit_before>use libc::size_t;
// use std::ffi::CStr;
use std::os::raw::{c_char, c_int};
use std::ptr;
use std::slice;
use webbundle::Bundle;

#[no_mangle]
pub struct WebBundle(Bundle);

/// Construct a new `WebBundle` from the provided `bytes`.
///
/// If the bytes passed in isn't a valid WebBundle representation,
/// this will return a null pointer.
///
/// # Safety
///
/// Make sure you destroy the WebBundle with [`webbundle_destroy()`] once you are
/// done with it.
///
/// [`webbundle_destroy()`]: fn.webbundle_destroy.html
#[no_mangle]
pub unsafe extern "C" fn webbundle_parse(bytes: *const c_char, length: size_t) -> *const WebBundle {
    let slice = slice::from_raw_parts(bytes as *mut u8, length as usize);
    match Bundle::from_bytes(slice) {
        Ok(bundle) => Box::into_raw(Box::new(WebBundle(bundle))),
        Err(_) => ptr::null(),
    }
}

/// Destroy a `WebBundle` once you are done with it.
///
/// # Safety
///
/// The passed `bundle` must be a valid WebBundle created by [`webbundle_parse()`] function.
///
/// [`webbundle_parse()`]: fn.webbundle_parse.html
#[no_mangle]
pub unsafe extern "C" fn webbundle_destroy(bundle: *mut WebBundle) {
    if !bundle.is_null() {
        drop(Box::from_raw(bundle));
    }
}

/// Copy the `bundle`'s primary_url into a user-provided `buffer`,
/// returning the number of bytes copied.
///
/// If user-provided buffer's length is not enough, this returns `-1`.
///
/// # Safety
///
/// - The passed `bundle` must be a valid WebBundle created by [`webbundle_parse()`] function.
/// - The user-provided `buffer` should have `length` length.
#[no_mangle]
pub unsafe extern "C" fn webbundle_primary_url(
    bundle: *const WebBundle,
    buffer: *mut c_char,
    length: size_t,
) -> c_int {
    if bundle.is_null() {
        return -1;
    }
    let bundle: &Bundle = &((*bundle).0);
    let uri = bundle.primary_url().to_string();

    let buffer: &mut [u8] = slice::from_raw_parts_mut(buffer as *mut u8, length as usize);

    if buffer.len() < uri.len() {
        return -1;
    }

    ptr::copy_nonoverlapping(uri.as_ptr(), buffer.as_mut_ptr(), uri.len());
    uri.len() as c_int
}
<commit_msg>Remove unnecessary #[no_mangle]<commit_after>use libc::size_t;
// use std::ffi::CStr;
use std::os::raw::{c_char, c_int};
use std::ptr;
use std::slice;
use webbundle::Bundle;

pub struct WebBundle(Bundle);

/// Construct a new `WebBundle` from the provided `bytes`.
///
/// If the bytes passed in isn't a valid WebBundle representation,
/// this will return a null pointer.
///
/// # Safety
///
/// Make sure you destroy the WebBundle with [`webbundle_destroy()`] once you are
/// done with it.
///
/// [`webbundle_destroy()`]: fn.webbundle_destroy.html
#[no_mangle]
pub unsafe extern "C" fn webbundle_parse(bytes: *const c_char, length: size_t) -> *const WebBundle {
    let slice = slice::from_raw_parts(bytes as *mut u8, length as usize);
    match Bundle::from_bytes(slice) {
        Ok(bundle) => Box::into_raw(Box::new(WebBundle(bundle))),
        Err(_) => ptr::null(),
    }
}

/// Destroy a `WebBundle` once you are done with it.
///
/// # Safety
///
/// The passed `bundle` must be a valid WebBundle created by [`webbundle_parse()`] function.
///
/// [`webbundle_parse()`]: fn.webbundle_parse.html
#[no_mangle]
pub unsafe extern "C" fn webbundle_destroy(bundle: *mut WebBundle) {
    if !bundle.is_null() {
        drop(Box::from_raw(bundle));
    }
}

/// Copy the `bundle`'s primary_url into a user-provided `buffer`,
/// returning the number of bytes copied.
///
/// If user-provided buffer's length is not enough, this returns `-1`.
///
/// # Safety
///
/// - The passed `bundle` must be a valid WebBundle created by [`webbundle_parse()`] function.
/// - The user-provided `buffer` should have `length` length.
#[no_mangle]
pub unsafe extern "C" fn webbundle_primary_url(
    bundle: *const WebBundle,
    buffer: *mut c_char,
    length: size_t,
) -> c_int {
    if bundle.is_null() {
        return -1;
    }
    let bundle: &Bundle = &((*bundle).0);
    let uri = bundle.primary_url().to_string();

    let buffer: &mut [u8] = slice::from_raw_parts_mut(buffer as *mut u8, length as usize);

    if buffer.len() < uri.len() {
        return -1;
    }

    ptr::copy_nonoverlapping(uri.as_ptr(), buffer.as_mut_ptr(), uri.len());
    uri.len() as c_int
}
<|endoftext|>


<commit_before>//! Utility routines for pretty-printing error messages.

use ir;
use ir::entities::Inst;
use ir::function::Function;
use isa::{RegInfo, TargetIsa};
use result::CodegenError;
use std::fmt;
use std::fmt::Write;
use std::string::{String, ToString};
use verifier::VerifierError;
use write::{decorate_function, FuncWriter, PlainWriter};

/// Pretty-print a verifier error.
pub fn pretty_verifier_error<'a>(
    func: &ir::Function,
    isa: Option<&TargetIsa>,
    func_w: Option<Box<FuncWriter + 'a>>,
    err: &VerifierError,
) -> String {
    let mut w = String::new();

    match err.location {
        ir::entities::AnyEntity::Inst(_) => {}
        _ => {
            // Print the error, because the pretty_function_error below won't do it since it isn't
            // tied to an instruction.
            writeln!(w, "verifier error summary: {}\n", err.to_string()).unwrap();
        }
    }

    decorate_function(
        &mut PrettyVerifierError(func_w.unwrap_or(Box::new(PlainWriter)), err),
        &mut w,
        func,
        isa,
    ).unwrap();
    w
}

struct PrettyVerifierError<'a>(Box<FuncWriter + 'a>, &'a VerifierError);

impl<'a> FuncWriter for PrettyVerifierError<'a> {
    fn write_instruction(
        &mut self,
        w: &mut Write,
        func: &Function,
        isa: Option<&TargetIsa>,
        inst: Inst,
        indent: usize,
    ) -> fmt::Result {
        pretty_function_error(w, func, isa, inst, indent, &mut *self.0, self.1)
    }

    fn write_preamble(
        &mut self,
        w: &mut Write,
        func: &Function,
        regs: Option<&RegInfo>,
    ) -> Result<bool, fmt::Error> {
        self.0.write_preamble(w, func, regs)
    }
}

/// Pretty-print a function verifier error.
fn pretty_function_error(
    w: &mut Write,
    func: &Function,
    isa: Option<&TargetIsa>,
    cur_inst: Inst,
    indent: usize,
    func_w: &mut FuncWriter,
    err: &VerifierError,
) -> fmt::Result {
    match err.location {
        ir::entities::AnyEntity::Inst(inst) if inst == cur_inst => {
            func_w.write_instruction(w, func, isa, cur_inst, indent)?;
            write!(w, "{1:0$}^", indent, "")?;
            for _c in cur_inst.to_string().chars() {
                write!(w, "~")?;
            }
            writeln!(w, " verifier {}\n", err.to_string())
        }
        _ => writeln!(
            w,
            "{1:0$}{2}",
            indent,
            "",
            func.dfg.display_inst(cur_inst, isa)
        ),
    }
}

/// Pretty-print a Cranelift error.
pub fn pretty_error(func: &ir::Function, isa: Option<&TargetIsa>, err: CodegenError) -> String {
    if let CodegenError::Verifier(e) = err {
        pretty_verifier_error(func, isa, None, &e)
    } else {
        err.to_string()
    }
}
<commit_msg>Add use declarations needed for no_std mode.<commit_after>//! Utility routines for pretty-printing error messages.

use ir;
use ir::entities::Inst;
use ir::function::Function;
use isa::{RegInfo, TargetIsa};
use result::CodegenError;
use std::boxed::Box;
use std::fmt;
use std::fmt::Write;
use std::string::{String, ToString};
use verifier::VerifierError;
use write::{decorate_function, FuncWriter, PlainWriter};

/// Pretty-print a verifier error.
pub fn pretty_verifier_error<'a>(
    func: &ir::Function,
    isa: Option<&TargetIsa>,
    func_w: Option<Box<FuncWriter + 'a>>,
    err: &VerifierError,
) -> String {
    let mut w = String::new();

    match err.location {
        ir::entities::AnyEntity::Inst(_) => {}
        _ => {
            // Print the error, because the pretty_function_error below won't do it since it isn't
            // tied to an instruction.
            writeln!(w, "verifier error summary: {}\n", err.to_string()).unwrap();
        }
    }

    decorate_function(
        &mut PrettyVerifierError(func_w.unwrap_or(Box::new(PlainWriter)), err),
        &mut w,
        func,
        isa,
    ).unwrap();
    w
}

struct PrettyVerifierError<'a>(Box<FuncWriter + 'a>, &'a VerifierError);

impl<'a> FuncWriter for PrettyVerifierError<'a> {
    fn write_instruction(
        &mut self,
        w: &mut Write,
        func: &Function,
        isa: Option<&TargetIsa>,
        inst: Inst,
        indent: usize,
    ) -> fmt::Result {
        pretty_function_error(w, func, isa, inst, indent, &mut *self.0, self.1)
    }

    fn write_preamble(
        &mut self,
        w: &mut Write,
        func: &Function,
        regs: Option<&RegInfo>,
    ) -> Result<bool, fmt::Error> {
        self.0.write_preamble(w, func, regs)
    }
}

/// Pretty-print a function verifier error.
fn pretty_function_error(
    w: &mut Write,
    func: &Function,
    isa: Option<&TargetIsa>,
    cur_inst: Inst,
    indent: usize,
    func_w: &mut FuncWriter,
    err: &VerifierError,
) -> fmt::Result {
    match err.location {
        ir::entities::AnyEntity::Inst(inst) if inst == cur_inst => {
            func_w.write_instruction(w, func, isa, cur_inst, indent)?;
            write!(w, "{1:0$}^", indent, "")?;
            for _c in cur_inst.to_string().chars() {
                write!(w, "~")?;
            }
            writeln!(w, " verifier {}\n", err.to_string())
        }
        _ => writeln!(
            w,
            "{1:0$}{2}",
            indent,
            "",
            func.dfg.display_inst(cur_inst, isa)
        ),
    }
}

/// Pretty-print a Cranelift error.
pub fn pretty_error(func: &ir::Function, isa: Option<&TargetIsa>, err: CodegenError) -> String {
    if let CodegenError::Verifier(e) = err {
        pretty_verifier_error(func, isa, None, &e)
    } else {
        err.to_string()
    }
}
<|endoftext|>


<commit_before>use super::*;
use std::sync::atomic::fence;
use std::sync::atomic::Ordering::AcqRel;
use std::sync::atomic::Ordering::Acquire;
use std::sync::atomic::Ordering::Release;

pub enum InsertSearchResult {
    External,
    Internal(NodeCellRef),
    RightNode(NodeCellRef),
}

pub enum InsertToNodeResult {
    NoSplit,
    Split(NodeWriteGuard, NodeCellRef, Option<EntryKey>),
    SplitParentChanged,
}

pub enum RemoveSearchResult {
    External,
    RightNode(NodeCellRef),
    Internal(NodeCellRef),
}

pub enum SubNodeStatus {
    ExtNodeEmpty,
    InNodeEmpty,
    Relocate(usize, usize),
    Merge(usize, usize),
    Ok,
}

pub struct NodeSplit {
    pub new_right_node: NodeCellRef,
    pub left_node_latch: NodeWriteGuard,
    pub pivot: EntryKey,
    pub parent_latch: NodeWriteGuard,
}

pub struct RebalancingNodes {
    pub left_guard: NodeWriteGuard,
    pub left_ref: NodeCellRef,
    pub right_guard: NodeWriteGuard,
    pub right_right_guard: NodeWriteGuard, // for external pointer modification
    pub parent: NodeWriteGuard,
    pub parent_pos: usize,
}

pub struct RemoveResult {
    pub rebalancing: Option<RebalancingNodes>,
    pub empty: bool,
    pub removed: bool,
}

pub enum NodeData {
    External(Box<ExtNode>),
    Internal(Box<InNode>),
    Empty(Box<EmptyNode>),
    None,
}

pub struct EmptyNode {
    pub left: Option<NodeCellRef>,
    pub right: NodeCellRef,
}

impl NodeData {
    pub fn is_none(&self) -> bool {
        match self {
            &NodeData::None => true,
            _ => false,
        }
    }
    pub fn is_empty(&self) -> bool {
        match self {
            &NodeData::Empty(ref n) => true,
            &NodeData::External(ref n) => n.len == 0,
            &NodeData::Internal(ref n) => n.len == 0,
            &NodeData::None => unreachable!(),
        }
    }
    pub fn is_empty_node(&self) -> bool {
        match self {
            &NodeData::Empty(ref n) => true,
            _ => false
        }
    }
    pub fn search(&self, key: &EntryKey) -> usize {
        let len = self.len();
        if self.is_ext() {
            self.extnode().search(key)
        } else {
            self.innode().search(key)
        }
    }

    pub fn remove(&mut self, pos: usize) {
        match self {
            &mut NodeData::External(ref mut node) => node.remove_at(pos),
            &mut NodeData::Internal(ref mut node) => node.remove_at(pos),
            &mut NodeData::None | &mut NodeData::Empty(_) => unreachable!(),
        }
    }
    pub fn is_ext(&self) -> bool {
        match self {
            &NodeData::External(_) => true,
            &NodeData::Internal(_) => false,
            &NodeData::None | &NodeData::Empty(_) => panic!(),
        }
    }
    pub fn keys(&self) -> &[EntryKey] {
        if self.is_ext() {
            &self.extnode().keys
        } else {
            &self.innode().keys
        }
    }

    pub fn first_key(&self) -> &EntryKey {
        &self.keys()[0]
    }

    pub fn last_key(&self) -> &EntryKey {
        &self.keys()[self.len() - 1]
    }

    pub fn len(&self) -> usize {
        match self {
            &NodeData::Internal(ref node) => node.len,
            &NodeData::External(ref node) => node.len,
            &NodeData::Empty(_) => 0,
            &NodeData::None => unreachable!(),
        }
    }

    // check if the node will be half full after an item have been removed
    pub fn is_half_full(&self) -> bool {
        if self.is_none() {
            true
        } else {
            let len = self.len();
            if len == 0 {
                return false;
            }
            len >= NUM_KEYS / 2 && len > 1
        }
    }

    pub fn cannot_merge(&self) -> bool {
        self.len() > NUM_KEYS / 2
    }

    pub fn extnode_mut(&mut self) -> &mut ExtNode {
        match self {
            &mut NodeData::External(ref mut node) => node,
            _ => unreachable!(self.type_name()),
        }
    }
    pub fn innode_mut(&mut self) -> &mut InNode {
        match self {
            &mut NodeData::Internal(ref mut n) => n,
            _ => unreachable!(self.type_name()),
        }
    }
    pub fn extnode(&self) -> &ExtNode {
        match self {
            &NodeData::External(ref node) => node,
            _ => unreachable!(self.type_name()),
        }
    }
    pub fn ext_id(&self) -> Id {
        match self {
            &NodeData::External(ref node) => node.id,
            &NodeData::None => Id::unit_id(),
            &NodeData::Internal(_) | &NodeData::Empty(_) => unreachable!(self.type_name()),
        }
    }
    pub fn innode(&self) -> &InNode {
        match self {
            &NodeData::Internal(ref n) => n,
            _ => unreachable!(self.type_name()),
        }
    }
    pub fn type_name(&self) -> &'static str {
        match self {
            &NodeData::Internal(_) => "internal",
            &NodeData::External(_) => "external",
            &NodeData::None => "none",
            &NodeData::Empty(_) => "empty",
        }
    }
    pub fn key_at_right_node(&self, key: &EntryKey) -> Option<&NodeCellRef> {
        if self.is_empty_node() || self.len() > 0 && self.last_key() < key {
            let right_node = self.right_ref().unwrap().read_unchecked();
            if !right_node.is_none() && (self.is_empty_node() || right_node.len() > 0 && right_node.first_key() <= key) {
                debug!(
                    "found key to put to right page {:?}/{:?}",
                    key, right_node.first_key()
                );
                return Some(self.right_ref().unwrap())
            }
        }
        return None;
    }

    pub fn left_ref_mut(&mut self) -> Option<&mut NodeCellRef> {
        match self {
            &mut NodeData::External(ref mut n) => Some(&mut n.prev),
            _ => None,
        }
    }

    pub fn left_ref(&self) -> Option<&NodeCellRef> {
        match self {
            &NodeData::External(ref n) => Some(&n.prev),
            _ => None,
        }
    }

    pub fn right_ref_mut(&mut self) -> Option<&mut NodeCellRef> {
        match self {
            &mut NodeData::External(ref mut n) => Some(&mut n.next),
            &mut NodeData::Internal(ref mut n) => Some(&mut n.right),
            &mut NodeData::Empty(ref mut n) => Some(&mut n.right),
            &mut NodeData::None => None,
        }
    }

    pub fn right_ref(&self) -> Option<&NodeCellRef> {
        match self {
            &NodeData::External(ref n) => Some(&n.next),
            &NodeData::Internal(ref n) => Some(&n.right),
            &NodeData::Empty(ref n) => Some(&n.right),
            &NodeData::None => None,
        }
    }

    pub fn has_vaild_right_node(&self) -> bool {
        self.right_ref().is_some()
    }
}

pub fn write_key_page(
    search_page: NodeWriteGuard,
    search_ref: &NodeCellRef,
    key: &EntryKey,
) -> (NodeWriteGuard, NodeCellRef) {
    if search_page.is_empty_node() || search_page.len() > 0 && search_page.last_key() < key {
        let right_ref = search_page.right_ref().unwrap();
        let right_node = write_node(right_ref);
        if !right_node.is_none() && (search_page.is_empty_node() || right_node.len() > 0 && right_node.first_key() <= key) {
            debug!("Will write {:?} from left {} node to right page, start with {:?}, keys {:?}",
                   key, search_page.type_name(), right_node.first_key(), right_node.keys());
            return write_key_page(right_node, right_ref, key);
        }
    }
    return (search_page, search_ref.clone());
}

const LATCH_FLAG: usize = !(!0 >> 1);

pub struct Node {
    data: UnsafeCell<NodeData>,
    cc: AtomicUsize,
}

impl Node {
    pub fn new(data: NodeData) -> Self {
        Node {
            data: UnsafeCell::new(data),
            cc: AtomicUsize::new(0),
        }
    }

    pub fn internal(innode: InNode) -> Self {
        Self::new(NodeData::Internal(box innode))
    }

    pub fn external(extnode: ExtNode) -> Self {
        Self::new(NodeData::External(box extnode))
    }

    pub fn none() -> Self {
        Self::new(NodeData::None)
    }
    pub fn none_ref() -> NodeCellRef {
        Arc::new(Node::none())
    }
    pub fn new_external(id: Id) -> Self {
        Self::external(ExtNode::new(id))
    }

    pub fn read_unchecked(&self) -> &NodeData {
        unsafe { &*self.data.get() }
    }

    pub fn version(&self) -> usize {
        node_version(self.cc.load(SeqCst))
    }
}

pub fn node_version(cc_num: usize) -> usize {
    cc_num & (!LATCH_FLAG)
}

pub fn write_node(node: &NodeCellRef) -> NodeWriteGuard {
    // debug!("acquiring node write lock");
    let cc = &node.cc;
    loop {
        let cc_num = cc.load(Relaxed);
        let expected = cc_num & (!LATCH_FLAG);
        debug_assert_eq!(expected & LATCH_FLAG, 0);
        match cc.compare_exchange_weak(expected, cc_num | LATCH_FLAG, Acquire, Relaxed) {
            Ok(num) if num == expected => {
                return NodeWriteGuard {
                    data: node.data.get(),
                    cc: &node.cc as *const AtomicUsize,
                    version: node_version(cc_num),
                    node_ref: node.clone()
                }
            }
            _ => {}
        }
    }
}

pub fn read_node<'a, F: FnMut(&NodeReadHandler) -> R + 'a, R: 'a>(node: &NodeCellRef, mut func: F) -> R {
    let mut handler = NodeReadHandler {
        ptr: node.data.get(),
        version: 0,
        node_ref: node.clone()
    };
    let cc = &node.cc;
    loop {
        let cc_num = cc.load(SeqCst);
        if cc_num & LATCH_FLAG == LATCH_FLAG {
            // debug!("read have a latch, retry {:b}", cc_num);
            continue;
        }
        handler.version = cc_num & (!LATCH_FLAG);
        let res = func(&handler);
        let new_cc_num = cc.load(SeqCst);
        if new_cc_num == cc_num {
            return res;
        }
        // debug!("read version changed, retry {:b}", cc_num);
    }
}

pub struct NodeWriteGuard {
    pub data: *mut NodeData,
    pub cc: *const AtomicUsize,
    pub version: usize,
    node_ref: NodeCellRef
}

impl Deref for NodeWriteGuard {
    type Target = NodeData;

    fn deref(&self) -> &<Self as Deref>::Target {
        debug_assert_ne!(self.data as usize, 0);
        unsafe { &*self.data }
    }
}

impl DerefMut for NodeWriteGuard {
    fn deref_mut(&mut self) -> &mut <Self as Deref>::Target {
        debug_assert_ne!(self.data as usize, 0);
        unsafe { &mut *self.data }
    }
}

impl Drop for NodeWriteGuard {
    fn drop(&mut self) {
        // cope with null pointer
        if self.cc as usize != 0 {
            let cc = unsafe { &*self.cc };
            let cc_num = cc.load(SeqCst);
            debug_assert_eq!(cc_num & LATCH_FLAG, LATCH_FLAG);
            cc.store((cc_num & (!LATCH_FLAG)) + 1, Release);
        }
    }
}

impl Default for NodeWriteGuard {
    fn default() -> Self {
        NodeWriteGuard {
            data: 0 as *mut NodeData,
            cc: 0 as *const AtomicUsize,
            version: 0,
            node_ref: Node::none_ref()
        }
    }
}

unsafe impl Sync for Node {}

pub struct NodeReadHandler {
    pub ptr: *const NodeData,
    pub version: usize,
    node_ref: NodeCellRef,
}

impl Deref for NodeReadHandler {
    type Target = NodeData;

    fn deref(&self) -> &<Self as Deref>::Target {
        unsafe { &*self.ptr }
    }
}

pub struct RemoveStatus {
    pub item_found: bool,
    pub removed: bool,
}

impl Default for Node {
    fn default() -> Self {
        Node::none()
    }
}

pub fn insert_into_split<T, S>(
    item: T,
    x: &mut S,
    y: &mut S,
    xlen: &mut usize,
    ylen: &mut usize,
    pos: usize,
) where
    S: Slice<Item = T> + BTreeSlice<T>,
    T: Default,
{
    debug!(
        "insert into split left len {}, right len {}, pos {}",
        xlen, ylen, pos
    );
    if pos < *xlen {
        debug!("insert into left part, pos: {}", pos);
        x.insert_at(item, pos, xlen);
    } else {
        let right_pos = pos - *xlen;
        debug!("insert into right part, pos: {}", right_pos);
        y.insert_at(item, right_pos, ylen);
    }
}
<commit_msg>avoid exceptions on debug messages<commit_after>use super::*;
use std::sync::atomic::fence;
use std::sync::atomic::Ordering::AcqRel;
use std::sync::atomic::Ordering::Acquire;
use std::sync::atomic::Ordering::Release;

pub enum InsertSearchResult {
    External,
    Internal(NodeCellRef),
    RightNode(NodeCellRef),
}

pub enum InsertToNodeResult {
    NoSplit,
    Split(NodeWriteGuard, NodeCellRef, Option<EntryKey>),
    SplitParentChanged,
}

pub enum RemoveSearchResult {
    External,
    RightNode(NodeCellRef),
    Internal(NodeCellRef),
}

pub enum SubNodeStatus {
    ExtNodeEmpty,
    InNodeEmpty,
    Relocate(usize, usize),
    Merge(usize, usize),
    Ok,
}

pub struct NodeSplit {
    pub new_right_node: NodeCellRef,
    pub left_node_latch: NodeWriteGuard,
    pub pivot: EntryKey,
    pub parent_latch: NodeWriteGuard,
}

pub struct RebalancingNodes {
    pub left_guard: NodeWriteGuard,
    pub left_ref: NodeCellRef,
    pub right_guard: NodeWriteGuard,
    pub right_right_guard: NodeWriteGuard, // for external pointer modification
    pub parent: NodeWriteGuard,
    pub parent_pos: usize,
}

pub struct RemoveResult {
    pub rebalancing: Option<RebalancingNodes>,
    pub empty: bool,
    pub removed: bool,
}

pub enum NodeData {
    External(Box<ExtNode>),
    Internal(Box<InNode>),
    Empty(Box<EmptyNode>),
    None,
}

pub struct EmptyNode {
    pub left: Option<NodeCellRef>,
    pub right: NodeCellRef,
}

impl NodeData {
    pub fn is_none(&self) -> bool {
        match self {
            &NodeData::None => true,
            _ => false,
        }
    }
    pub fn is_empty(&self) -> bool {
        match self {
            &NodeData::Empty(ref n) => true,
            &NodeData::External(ref n) => n.len == 0,
            &NodeData::Internal(ref n) => n.len == 0,
            &NodeData::None => unreachable!(),
        }
    }
    pub fn is_empty_node(&self) -> bool {
        match self {
            &NodeData::Empty(ref n) => true,
            _ => false
        }
    }
    pub fn search(&self, key: &EntryKey) -> usize {
        let len = self.len();
        if self.is_ext() {
            self.extnode().search(key)
        } else {
            self.innode().search(key)
        }
    }

    pub fn remove(&mut self, pos: usize) {
        match self {
            &mut NodeData::External(ref mut node) => node.remove_at(pos),
            &mut NodeData::Internal(ref mut node) => node.remove_at(pos),
            &mut NodeData::None | &mut NodeData::Empty(_) => unreachable!(),
        }
    }
    pub fn is_ext(&self) -> bool {
        match self {
            &NodeData::External(_) => true,
            &NodeData::Internal(_) => false,
            &NodeData::None | &NodeData::Empty(_) => panic!(),
        }
    }
    pub fn keys(&self) -> &[EntryKey] {
        if self.is_ext() {
            &self.extnode().keys
        } else {
            &self.innode().keys
        }
    }

    pub fn first_key(&self) -> &EntryKey {
        &self.keys()[0]
    }

    pub fn last_key(&self) -> &EntryKey {
        &self.keys()[self.len() - 1]
    }

    pub fn len(&self) -> usize {
        match self {
            &NodeData::Internal(ref node) => node.len,
            &NodeData::External(ref node) => node.len,
            &NodeData::Empty(_) => 0,
            &NodeData::None => unreachable!(),
        }
    }

    // check if the node will be half full after an item have been removed
    pub fn is_half_full(&self) -> bool {
        if self.is_none() {
            true
        } else {
            let len = self.len();
            if len == 0 {
                return false;
            }
            len >= NUM_KEYS / 2 && len > 1
        }
    }

    pub fn cannot_merge(&self) -> bool {
        self.len() > NUM_KEYS / 2
    }

    pub fn extnode_mut(&mut self) -> &mut ExtNode {
        match self {
            &mut NodeData::External(ref mut node) => node,
            _ => unreachable!(self.type_name()),
        }
    }
    pub fn innode_mut(&mut self) -> &mut InNode {
        match self {
            &mut NodeData::Internal(ref mut n) => n,
            _ => unreachable!(self.type_name()),
        }
    }
    pub fn extnode(&self) -> &ExtNode {
        match self {
            &NodeData::External(ref node) => node,
            _ => unreachable!(self.type_name()),
        }
    }
    pub fn ext_id(&self) -> Id {
        match self {
            &NodeData::External(ref node) => node.id,
            &NodeData::None => Id::unit_id(),
            &NodeData::Internal(_) | &NodeData::Empty(_) => unreachable!(self.type_name()),
        }
    }
    pub fn innode(&self) -> &InNode {
        match self {
            &NodeData::Internal(ref n) => n,
            _ => unreachable!(self.type_name()),
        }
    }
    pub fn type_name(&self) -> &'static str {
        match self {
            &NodeData::Internal(_) => "internal",
            &NodeData::External(_) => "external",
            &NodeData::None => "none",
            &NodeData::Empty(_) => "empty",
        }
    }
    pub fn key_at_right_node(&self, key: &EntryKey) -> Option<&NodeCellRef> {
        if self.is_empty_node() || self.len() > 0 && self.last_key() < key {
            let right_node = self.right_ref().unwrap().read_unchecked();
            if !right_node.is_none() && (self.is_empty_node() || right_node.len() > 0 && right_node.first_key() <= key) {
                debug!(
                    "found key to put to right page {:?}/{:?}",
                    key, right_node.first_key()
                );
                return Some(self.right_ref().unwrap())
            }
        }
        return None;
    }

    pub fn left_ref_mut(&mut self) -> Option<&mut NodeCellRef> {
        match self {
            &mut NodeData::External(ref mut n) => Some(&mut n.prev),
            _ => None,
        }
    }

    pub fn left_ref(&self) -> Option<&NodeCellRef> {
        match self {
            &NodeData::External(ref n) => Some(&n.prev),
            _ => None,
        }
    }

    pub fn right_ref_mut(&mut self) -> Option<&mut NodeCellRef> {
        match self {
            &mut NodeData::External(ref mut n) => Some(&mut n.next),
            &mut NodeData::Internal(ref mut n) => Some(&mut n.right),
            &mut NodeData::Empty(ref mut n) => Some(&mut n.right),
            &mut NodeData::None => None,
        }
    }

    pub fn right_ref(&self) -> Option<&NodeCellRef> {
        match self {
            &NodeData::External(ref n) => Some(&n.next),
            &NodeData::Internal(ref n) => Some(&n.right),
            &NodeData::Empty(ref n) => Some(&n.right),
            &NodeData::None => None,
        }
    }

    pub fn has_vaild_right_node(&self) -> bool {
        self.right_ref().is_some()
    }
}

pub fn write_key_page(
    search_page: NodeWriteGuard,
    search_ref: &NodeCellRef,
    key: &EntryKey,
) -> (NodeWriteGuard, NodeCellRef) {
    if search_page.is_empty_node() || search_page.len() > 0 && search_page.last_key() < key {
        let right_ref = search_page.right_ref().unwrap();
        let right_node = write_node(right_ref);
        if !right_node.is_none() && (search_page.is_empty_node() || right_node.len() > 0 && right_node.first_key() <= key) {
            debug!("Will write {:?} from left {} node to right page, start with {:?}, keys {:?}",
                   key, search_page.type_name(),
                   if right_node.is_empty_node() { smallvec!(0) } else { right_node.first_key().clone() },
                   right_node.keys());
            return write_key_page(right_node, right_ref, key);
        }
    }
    return (search_page, search_ref.clone());
}

const LATCH_FLAG: usize = !(!0 >> 1);

pub struct Node {
    data: UnsafeCell<NodeData>,
    cc: AtomicUsize,
}

impl Node {
    pub fn new(data: NodeData) -> Self {
        Node {
            data: UnsafeCell::new(data),
            cc: AtomicUsize::new(0),
        }
    }

    pub fn internal(innode: InNode) -> Self {
        Self::new(NodeData::Internal(box innode))
    }

    pub fn external(extnode: ExtNode) -> Self {
        Self::new(NodeData::External(box extnode))
    }

    pub fn none() -> Self {
        Self::new(NodeData::None)
    }
    pub fn none_ref() -> NodeCellRef {
        Arc::new(Node::none())
    }
    pub fn new_external(id: Id) -> Self {
        Self::external(ExtNode::new(id))
    }

    pub fn read_unchecked(&self) -> &NodeData {
        unsafe { &*self.data.get() }
    }

    pub fn version(&self) -> usize {
        node_version(self.cc.load(SeqCst))
    }
}

pub fn node_version(cc_num: usize) -> usize {
    cc_num & (!LATCH_FLAG)
}

pub fn write_node(node: &NodeCellRef) -> NodeWriteGuard {
    // debug!("acquiring node write lock");
    let cc = &node.cc;
    loop {
        let cc_num = cc.load(Relaxed);
        let expected = cc_num & (!LATCH_FLAG);
        debug_assert_eq!(expected & LATCH_FLAG, 0);
        match cc.compare_exchange_weak(expected, cc_num | LATCH_FLAG, Acquire, Relaxed) {
            Ok(num) if num == expected => {
                return NodeWriteGuard {
                    data: node.data.get(),
                    cc: &node.cc as *const AtomicUsize,
                    version: node_version(cc_num),
                    node_ref: node.clone()
                }
            }
            _ => {}
        }
    }
}

pub fn read_node<'a, F: FnMut(&NodeReadHandler) -> R + 'a, R: 'a>(node: &NodeCellRef, mut func: F) -> R {
    let mut handler = NodeReadHandler {
        ptr: node.data.get(),
        version: 0,
        node_ref: node.clone()
    };
    let cc = &node.cc;
    loop {
        let cc_num = cc.load(SeqCst);
        if cc_num & LATCH_FLAG == LATCH_FLAG {
            // debug!("read have a latch, retry {:b}", cc_num);
            continue;
        }
        handler.version = cc_num & (!LATCH_FLAG);
        let res = func(&handler);
        let new_cc_num = cc.load(SeqCst);
        if new_cc_num == cc_num {
            return res;
        }
        // debug!("read version changed, retry {:b}", cc_num);
    }
}

pub struct NodeWriteGuard {
    pub data: *mut NodeData,
    pub cc: *const AtomicUsize,
    pub version: usize,
    node_ref: NodeCellRef
}

impl Deref for NodeWriteGuard {
    type Target = NodeData;

    fn deref(&self) -> &<Self as Deref>::Target {
        debug_assert_ne!(self.data as usize, 0);
        unsafe { &*self.data }
    }
}

impl DerefMut for NodeWriteGuard {
    fn deref_mut(&mut self) -> &mut <Self as Deref>::Target {
        debug_assert_ne!(self.data as usize, 0);
        unsafe { &mut *self.data }
    }
}

impl Drop for NodeWriteGuard {
    fn drop(&mut self) {
        // cope with null pointer
        if self.cc as usize != 0 {
            let cc = unsafe { &*self.cc };
            let cc_num = cc.load(SeqCst);
            debug_assert_eq!(cc_num & LATCH_FLAG, LATCH_FLAG);
            cc.store((cc_num & (!LATCH_FLAG)) + 1, Release);
        }
    }
}

impl Default for NodeWriteGuard {
    fn default() -> Self {
        NodeWriteGuard {
            data: 0 as *mut NodeData,
            cc: 0 as *const AtomicUsize,
            version: 0,
            node_ref: Node::none_ref()
        }
    }
}

unsafe impl Sync for Node {}

pub struct NodeReadHandler {
    pub ptr: *const NodeData,
    pub version: usize,
    node_ref: NodeCellRef,
}

impl Deref for NodeReadHandler {
    type Target = NodeData;

    fn deref(&self) -> &<Self as Deref>::Target {
        unsafe { &*self.ptr }
    }
}

pub struct RemoveStatus {
    pub item_found: bool,
    pub removed: bool,
}

impl Default for Node {
    fn default() -> Self {
        Node::none()
    }
}

pub fn insert_into_split<T, S>(
    item: T,
    x: &mut S,
    y: &mut S,
    xlen: &mut usize,
    ylen: &mut usize,
    pos: usize,
) where
    S: Slice<Item = T> + BTreeSlice<T>,
    T: Default,
{
    debug!(
        "insert into split left len {}, right len {}, pos {}",
        xlen, ylen, pos
    );
    if pos < *xlen {
        debug!("insert into left part, pos: {}", pos);
        x.insert_at(item, pos, xlen);
    } else {
        let right_pos = pos - *xlen;
        debug!("insert into right part, pos: {}", right_pos);
        y.insert_at(item, right_pos, ylen);
    }
}
<|endoftext|>


<commit_before>//! Provides the following procedural derive macros:
//!
//! - `#[derive(Encode)]`
//! - `#[derive(Decode)]`
//! - `#[derive(TreeHash)]`
//!
//! These macros provide SSZ encoding/decoding for a `struct`. Fields are encoded/decoded in the
//! order they are defined.
//!
//! Presently, only `structs` with named fields are supported. `enum`s and tuple-structs are
//! unsupported.
//!
//! Example:
//! ```
//! use ssz::{ssz_encode, Decodable};
//! use ssz_derive::{Encode, Decode};
//!
//! #[derive(Encode, Decode)]
//! struct Foo {
//!     pub bar: bool,
//!     pub baz: u64,
//! }
//!
//! fn main() {
//!     let foo = Foo {
//!         bar: true,
//!         baz: 42,
//!     };
//!
//!     let bytes = ssz_encode(&foo);
//!
//!     let (decoded_foo, _i) = Foo::ssz_decode(&bytes, 0).unwrap();
//!
//!     assert_eq!(foo.baz, decoded_foo.baz);
//! }
//! ```

extern crate proc_macro;

use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, DeriveInput};

/// Returns a Vec of `syn::Ident` for each named field in the struct.
///
/// # Panics
/// Any unnamed struct field (like in a tuple struct) will raise a panic at compile time.
fn get_named_field_idents<'a>(struct_data: &'a syn::DataStruct) -> Vec<&'a syn::Ident> {
    struct_data
        .fields
        .iter()
        .map(|f| match &f.ident {
            Some(ref ident) => ident,
            _ => panic!("ssz_derive only supports named struct fields."),
        })
        .collect()
}

/// Implements `ssz::Encodable` for some `struct`.
///
/// Fields are encoded in the order they are defined.
#[proc_macro_derive(Encode)]
pub fn ssz_encode_derive(input: TokenStream) -> TokenStream {
    let item = parse_macro_input!(input as DeriveInput);

    let name = &item.ident;

    let struct_data = match &item.data {
        syn::Data::Struct(s) => s,
        _ => panic!("ssz_derive only supports structs."),
    };

    let field_idents = get_named_field_idents(&struct_data);

    let output = quote! {
        impl ssz::Encodable for #name {
            fn ssz_append(&self, s: &mut ssz::SszStream) {
                #(
                    s.append(&self.#field_idents);
                )*
            }
        }
    };
    output.into()
}

/// Implements `ssz::Decodable` for some `struct`.
///
/// Fields are decoded in the order they are defined.
#[proc_macro_derive(Decode)]
pub fn ssz_decode_derive(input: TokenStream) -> TokenStream {
    let item = parse_macro_input!(input as DeriveInput);

    let name = &item.ident;

    let struct_data = match &item.data {
        syn::Data::Struct(s) => s,
        _ => panic!("ssz_derive only supports structs."),
    };

    let field_idents = get_named_field_idents(&struct_data);

    // Using a var in an iteration always consumes the var, therefore we must make a `fields_a` and
    // a `fields_b` in order to perform two loops.
    //
    // https://github.com/dtolnay/quote/issues/8
    let field_idents_a = &field_idents;
    let field_idents_b = &field_idents;

    let output = quote! {
        impl ssz::Decodable for #name {
            fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), ssz::DecodeError> {
                #(
                    let (#field_idents_a, i) = <_>::ssz_decode(bytes, i)?;
                )*

                Ok((
                    Self {
                        #(
                            #field_idents_b,
                        )*
                    },
                    i
                ))
            }
        }
    };
    output.into()
}

/// Implements `ssz::TreeHash` for some `struct`.
///
/// Fields are processed in the order they are defined.
#[proc_macro_derive(TreeHash)]
pub fn ssz_tree_hash_derive(input: TokenStream) -> TokenStream {
    let item = parse_macro_input!(input as DeriveInput);

    let name = &item.ident;

    let struct_data = match &item.data {
        syn::Data::Struct(s) => s,
        _ => panic!("ssz_derive only supports structs."),
    };

    let field_idents = get_named_field_idents(&struct_data);

    let output = quote! {
        impl ssz::TreeHash for #name {
            fn hash_tree_root(&self) -> Vec<u8> {
                let mut list: Vec<Vec<u8>> = Vec::new();
                #(
                    list.push(self.#field_idents.hash_tree_root());
                )*

                ssz::merkle_hash(&mut list)
            }
        }
    };
    output.into()
}

/// Returns `true` if some `Ident` should be considered to be a signature type.
fn type_ident_is_signature(ident: &syn::Ident) -> bool {
    match ident.to_string().as_ref() {
        "Signature" => true,
        "AggregateSignature" => true,
        _ => false,
    }
}

/// Takes a `Field` where the type (`ty`) portion is a path (e.g., `types::Signature`) and returns
/// the final `Ident` in that path.
///
/// E.g., for `types::Signature` returns `Signature`.
fn final_type_ident(field: &syn::Field) -> &syn::Ident {
    match &field.ty {
        syn::Type::Path(path) => &path.path.segments.last().unwrap().value().ident,
        _ => panic!("ssz_derive only supports Path types."),
    }
}

/// Implements `ssz::TreeHash` for some `struct`, whilst excluding any fields following and
/// including a field that is of type "Signature" or "AggregateSignature".
///
/// See:
/// https://github.com/ethereum/eth2.0-specs/blob/master/specs/simple-serialize.md#signed-roots
///
/// This is a rather horrendous macro, it will read the type of the object as a string and decide
/// if it's a signature by matching that string against "Signature" or "AggregateSignature". So,
/// it's important that you use those exact words as your type -- don't alias it to something else.
///
/// If you can think of a better way to do this, please make an issue!
///
/// Fields are processed in the order they are defined.
#[proc_macro_derive(SignedRoot)]
pub fn ssz_signed_root_derive(input: TokenStream) -> TokenStream {
    let item = parse_macro_input!(input as DeriveInput);

    let name = &item.ident;

    let struct_data = match &item.data {
        syn::Data::Struct(s) => s,
        _ => panic!("ssz_derive only supports structs."),
    };

    let mut field_idents: Vec<&syn::Ident> = vec![];

    for field in struct_data.fields.iter() {
        let final_type_ident = final_type_ident(&field);

        if type_ident_is_signature(final_type_ident) {
            break;
        } else {
            let ident = field
                .ident
                .as_ref()
                .expect("ssz_derive only supports named_struct fields.");
            field_idents.push(ident);
        }
    }

    let output = quote! {
        impl ssz::SignedRoot for #name {
            fn signed_root(&self) -> Vec<u8> {
                let mut list: Vec<Vec<u8>> = Vec::new();
                #(
                    list.push(self.#field_idents.hash_tree_root());
                )*

                ssz::merkle_hash(&mut list)
            }
        }
    };
    output.into()
}
<commit_msg>Add field idents support to ssz_derive.<commit_after>//! Provides the following procedural derive macros:
//!
//! - `#[derive(Encode)]`
//! - `#[derive(Decode)]`
//! - `#[derive(TreeHash)]`
//!
//! These macros provide SSZ encoding/decoding for a `struct`. Fields are encoded/decoded in the
//! order they are defined.
//!
//! Presently, only `structs` with named fields are supported. `enum`s and tuple-structs are
//! unsupported.
//!
//! Example:
//! ```
//! use ssz::{ssz_encode, Decodable};
//! use ssz_derive::{Encode, Decode};
//!
//! #[derive(Encode, Decode)]
//! struct Foo {
//!     pub bar: bool,
//!     pub baz: u64,
//! }
//!
//! fn main() {
//!     let foo = Foo {
//!         bar: true,
//!         baz: 42,
//!     };
//!
//!     let bytes = ssz_encode(&foo);
//!
//!     let (decoded_foo, _i) = Foo::ssz_decode(&bytes, 0).unwrap();
//!
//!     assert_eq!(foo.baz, decoded_foo.baz);
//! }
//! ```

extern crate proc_macro;

use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, DeriveInput};

/// Returns a Vec of `syn::Ident` for each named field in the struct.
///
/// # Panics
/// Any unnamed struct field (like in a tuple struct) will raise a panic at compile time.
fn get_named_field_idents<'a>(struct_data: &'a syn::DataStruct) -> Vec<&'a syn::Ident> {
    struct_data
        .fields
        .iter()
        .map(|f| match &f.ident {
            Some(ref ident) => ident,
            _ => panic!("ssz_derive only supports named struct fields."),
        })
        .collect()
}

/// Returns a Vec of `syn::Ident` for each named field in the struct, whilst filtering out fields
/// that should not be serialized.
///
/// # Panics
/// Any unnamed struct field (like in a tuple struct) will raise a panic at compile time.
fn get_serializable_named_field_idents<'a>(
    struct_data: &'a syn::DataStruct,
) -> Vec<&'a syn::Ident> {
    struct_data
        .fields
        .iter()
        .filter_map(|f| {
            if should_skip_serializing(&f) {
                None
            } else {
                Some(match &f.ident {
                    Some(ref ident) => ident,
                    _ => panic!("ssz_derive only supports named struct fields."),
                })
            }
        })
        .collect()
}

/// Returns true if some field has an attribute declaring it should not be serialized.
///
/// The field attribute is: `#[ssz(skip_serializing)]`
fn should_skip_serializing(field: &syn::Field) -> bool {
    for attr in &field.attrs {
        if attr.tts.to_string() == "( skip_serializing )" {
            return true;
        }
    }
    false
}

/// Implements `ssz::Encodable` for some `struct`.
///
/// Fields are encoded in the order they are defined.
#[proc_macro_derive(Encode, attributes(ssz))]
pub fn ssz_encode_derive(input: TokenStream) -> TokenStream {
    let item = parse_macro_input!(input as DeriveInput);

    let name = &item.ident;

    let struct_data = match &item.data {
        syn::Data::Struct(s) => s,
        _ => panic!("ssz_derive only supports structs."),
    };

    let field_idents = get_serializable_named_field_idents(&struct_data);

    let output = quote! {
        impl ssz::Encodable for #name {
            fn ssz_append(&self, s: &mut ssz::SszStream) {
                #(
                    s.append(&self.#field_idents);
                )*
            }
        }
    };
    output.into()
}

/// Returns true if some field has an attribute declaring it should not be deserialized.
///
/// The field attribute is: `#[ssz(skip_deserializing)]`
fn should_skip_deserializing(field: &syn::Field) -> bool {
    for attr in &field.attrs {
        if attr.tts.to_string() == "( skip_deserializing )" {
            return true;
        }
    }
    false
}

/// Implements `ssz::Decodable` for some `struct`.
///
/// Fields are decoded in the order they are defined.
#[proc_macro_derive(Decode)]
pub fn ssz_decode_derive(input: TokenStream) -> TokenStream {
    let item = parse_macro_input!(input as DeriveInput);

    let name = &item.ident;

    let struct_data = match &item.data {
        syn::Data::Struct(s) => s,
        _ => panic!("ssz_derive only supports structs."),
    };

    let all_idents = get_named_field_idents(&struct_data);

    // Build quotes for fields that should be deserialized and those that should be built from
    // `Default`.
    let mut quotes = vec![];
    for field in &struct_data.fields {
        match &field.ident {
            Some(ref ident) => {
                if should_skip_deserializing(field) {
                    quotes.push(quote! {
                        let #ident = <_>::default();
                    });
                } else {
                    quotes.push(quote! {
                        let (#ident, i) = <_>::ssz_decode(bytes, i)?;
                    });
                }
            }
            _ => panic!("ssz_derive only supports named struct fields."),
        };
    }

    let output = quote! {
        impl ssz::Decodable for #name {
            fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), ssz::DecodeError> {
                #(
                    #quotes
                )*

                Ok((
                    Self {
                        #(
                            #all_idents,
                        )*
                    },
                    i
                ))
            }
        }
    };
    output.into()
}

/// Returns a Vec of `syn::Ident` for each named field in the struct, whilst filtering out fields
/// that should not be tree hashed.
///
/// # Panics
/// Any unnamed struct field (like in a tuple struct) will raise a panic at compile time.
fn get_tree_hashable_named_field_idents<'a>(
    struct_data: &'a syn::DataStruct,
) -> Vec<&'a syn::Ident> {
    struct_data
        .fields
        .iter()
        .filter_map(|f| {
            if should_skip_tree_hash(&f) {
                None
            } else {
                Some(match &f.ident {
                    Some(ref ident) => ident,
                    _ => panic!("ssz_derive only supports named struct fields."),
                })
            }
        })
        .collect()
}

/// Returns true if some field has an attribute declaring it should not be tree-hashed.
///
/// The field attribute is: `#[tree_hash(skip_hashing)]`
fn should_skip_tree_hash(field: &syn::Field) -> bool {
    for attr in &field.attrs {
        if attr.tts.to_string() == "( skip_hashing )" {
            return true;
        }
    }
    false
}

/// Implements `ssz::TreeHash` for some `struct`.
///
/// Fields are processed in the order they are defined.
#[proc_macro_derive(TreeHash, attributes(tree_hash))]
pub fn ssz_tree_hash_derive(input: TokenStream) -> TokenStream {
    let item = parse_macro_input!(input as DeriveInput);

    let name = &item.ident;

    let struct_data = match &item.data {
        syn::Data::Struct(s) => s,
        _ => panic!("ssz_derive only supports structs."),
    };

    let field_idents = get_tree_hashable_named_field_idents(&struct_data);

    let output = quote! {
        impl ssz::TreeHash for #name {
            fn hash_tree_root(&self) -> Vec<u8> {
                let mut list: Vec<Vec<u8>> = Vec::new();
                #(
                    list.push(self.#field_idents.hash_tree_root());
                )*

                ssz::merkle_hash(&mut list)
            }
        }
    };
    output.into()
}

/// Returns `true` if some `Ident` should be considered to be a signature type.
fn type_ident_is_signature(ident: &syn::Ident) -> bool {
    match ident.to_string().as_ref() {
        "Signature" => true,
        "AggregateSignature" => true,
        _ => false,
    }
}

/// Takes a `Field` where the type (`ty`) portion is a path (e.g., `types::Signature`) and returns
/// the final `Ident` in that path.
///
/// E.g., for `types::Signature` returns `Signature`.
fn final_type_ident(field: &syn::Field) -> &syn::Ident {
    match &field.ty {
        syn::Type::Path(path) => &path.path.segments.last().unwrap().value().ident,
        _ => panic!("ssz_derive only supports Path types."),
    }
}

/// Implements `ssz::TreeHash` for some `struct`, whilst excluding any fields following and
/// including a field that is of type "Signature" or "AggregateSignature".
///
/// See:
/// https://github.com/ethereum/eth2.0-specs/blob/master/specs/simple-serialize.md#signed-roots
///
/// This is a rather horrendous macro, it will read the type of the object as a string and decide
/// if it's a signature by matching that string against "Signature" or "AggregateSignature". So,
/// it's important that you use those exact words as your type -- don't alias it to something else.
///
/// If you can think of a better way to do this, please make an issue!
///
/// Fields are processed in the order they are defined.
#[proc_macro_derive(SignedRoot)]
pub fn ssz_signed_root_derive(input: TokenStream) -> TokenStream {
    let item = parse_macro_input!(input as DeriveInput);

    let name = &item.ident;

    let struct_data = match &item.data {
        syn::Data::Struct(s) => s,
        _ => panic!("ssz_derive only supports structs."),
    };

    let mut field_idents: Vec<&syn::Ident> = vec![];

    for field in struct_data.fields.iter() {
        let final_type_ident = final_type_ident(&field);

        if type_ident_is_signature(final_type_ident) {
            break;
        } else {
            let ident = field
                .ident
                .as_ref()
                .expect("ssz_derive only supports named_struct fields.");
            field_idents.push(ident);
        }
    }

    let output = quote! {
        impl ssz::SignedRoot for #name {
            fn signed_root(&self) -> Vec<u8> {
                let mut list: Vec<Vec<u8>> = Vec::new();
                #(
                    list.push(self.#field_idents.hash_tree_root());
                )*

                ssz::merkle_hash(&mut list)
            }
        }
    };
    output.into()
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
use msg::constellation_msg::PipelineId;
use rustc_serialize::{json, Encoder, Encodable};
use std::cell::RefCell;
use std::collections::{HashMap, VecDeque};
use std::mem;
use std::net::TcpStream;
use std::sync::mpsc::channel;
use std::sync::{Arc, Mutex};
use std::thread::sleep_ms;

use actor::{Actor, ActorRegistry, ActorMessageStatus};
use actors::framerate::FramerateActor;
use actors::memory::{MemoryActor, TimelineMemoryReply};
use devtools_traits::DevtoolScriptControlMsg;
use devtools_traits::DevtoolScriptControlMsg::{SetTimelineMarkers, DropTimelineMarkers};
use devtools_traits::{PreciseTime, TimelineMarker, TracingMetadata, TimelineMarkerType};
use protocol::JsonPacketStream;
use util::task;

pub struct TimelineActor {
    name: String,
    script_sender: IpcSender<DevtoolScriptControlMsg>,
    marker_types: Vec<TimelineMarkerType>,
    pipeline: PipelineId,
    is_recording: Arc<Mutex<bool>>,
    stream: RefCell<Option<TcpStream>>,

    framerate_actor: RefCell<Option<String>>,
    memory_actor: RefCell<Option<String>>,
}

struct Emitter {
    from: String,
    stream: TcpStream,
    markers: Vec<TimelineMarkerReply>,
    registry: Arc<Mutex<ActorRegistry>>,
    start_stamp: PreciseTime,

    framerate_actor: Option<String>,
    memory_actor: Option<String>,
}

#[derive(RustcEncodable)]
struct IsRecordingReply {
    from: String,
    value: bool
}

#[derive(RustcEncodable)]
struct StartReply {
    from: String,
    value: HighResolutionStamp,
}

#[derive(RustcEncodable)]
struct StopReply {
    from: String,
    value: HighResolutionStamp,
}

#[derive(RustcEncodable)]
struct TimelineMarkerReply {
    name: String,
    start: HighResolutionStamp,
    end: HighResolutionStamp,
    stack: Option<Vec<()>>,
    endStack: Option<Vec<()>>,
}

#[derive(RustcEncodable)]
struct MarkersEmitterReply {
    __type__: String,
    markers: Vec<TimelineMarkerReply>,
    from: String,
    endTime: HighResolutionStamp,
}

#[derive(RustcEncodable)]
struct MemoryEmitterReply {
    __type__: String,
    from: String,
    delta: HighResolutionStamp,
    measurement: TimelineMemoryReply,
}

#[derive(RustcEncodable)]
struct FramerateEmitterReply {
    __type__: String,
    from: String,
    delta: HighResolutionStamp,
    timestamps: Vec<HighResolutionStamp>,
}

/// HighResolutionStamp is struct that contains duration in milliseconds
/// with accuracy to microsecond that shows how much time has passed since
/// actor registry inited
/// analog https://w3c.github.io/hr-time/#sec-DOMHighResTimeStamp
pub struct HighResolutionStamp(f64);

impl HighResolutionStamp {
    pub fn new(start_stamp: PreciseTime, time: PreciseTime) -> HighResolutionStamp {
        let duration = start_stamp.to(time).num_microseconds()
                                  .expect("Too big duration in microseconds");
        HighResolutionStamp(duration as f64 / 1000 as f64)
    }

    pub fn wrap(time: f64) -> HighResolutionStamp {
        HighResolutionStamp(time)
    }
}

impl Encodable for HighResolutionStamp {
    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        self.0.encode(s)
    }
}

static DEFAULT_TIMELINE_DATA_PULL_TIMEOUT: u32 = 200; //ms

impl TimelineActor {
    pub fn new(name: String,
               pipeline: PipelineId,
               script_sender: IpcSender<DevtoolScriptControlMsg>) -> TimelineActor {

        let marker_types = vec!(TimelineMarkerType::Reflow,
                                TimelineMarkerType::DOMEvent);

        TimelineActor {
            name: name,
            pipeline: pipeline,
            marker_types: marker_types,
            script_sender: script_sender,
            is_recording: Arc::new(Mutex::new(false)),
            stream: RefCell::new(None),

            framerate_actor: RefCell::new(None),
            memory_actor: RefCell::new(None),
        }
    }

    fn pull_timeline_data(&self, receiver: IpcReceiver<TimelineMarker>, mut emitter: Emitter) {
        let is_recording = self.is_recording.clone();

        if !*is_recording.lock().unwrap() {
            return;
        }

        /// Select root(with depth 0) TimelineMarker pair (IntervalStart + IntervalEnd)
        /// from queue and add marker to emitter
        /// Return true if closed (IntervalStart + IntervalEnd) pair was founded
        fn group(queue: &mut VecDeque<TimelineMarker>, depth: usize,
                 start_payload: Option<TimelineMarker>, emitter: &mut Emitter) -> bool {

            if let Some(start_payload) = start_payload {
                if start_payload.metadata != TracingMetadata::IntervalStart {
                    panic!("Start payload doesn't have metadata IntervalStart");
                }

                if let Some(end_payload) = queue.pop_front() {
                    match end_payload.metadata {
                        TracingMetadata::IntervalEnd => {
                            if depth == 0 {
                                // Emit TimelineMarkerReply, pair was found
                                emitter.add_marker(start_payload, end_payload);
                            }
                            return true;
                        }
                        TracingMetadata::IntervalStart => {
                            if group(queue, depth + 1, Some(end_payload), emitter) {
                                return group(queue, depth, Some(start_payload), emitter);
                            } else {
                                queue.push_front(start_payload);
                            }
                        }
                        _ => panic!("Unknown tracingMetadata")
                    }
                } else {
                    queue.push_front(start_payload);
                }
            }

            false
        }

        task::spawn_named("PullTimelineMarkers".to_string(), move || {
            let mut queues = HashMap::new();
            queues.insert("Reflow".to_string(), VecDeque::new());
            queues.insert("DOMEvent".to_string(), VecDeque::new());

            loop {
                if !*is_recording.lock().unwrap() {
                    break;
                }

                // Creating queues by marker.name
                loop {
                    match receiver.try_recv() {
                        Ok(marker) => {
                            if let Some(list) = queues.get_mut(&marker.name) {
                                list.push_back(marker);
                            }
                        }

                        Err(_) => break
                    }
                }

                // Emit all markers
                for (_, queue) in &mut queues {
                    let start_payload = queue.pop_front();
                    group(queue, 0, start_payload, &mut emitter);
                }
                emitter.send();

                sleep_ms(DEFAULT_TIMELINE_DATA_PULL_TIMEOUT);
            }
        });
    }
}

impl Actor for TimelineActor {
    fn name(&self) -> String {
        self.name.clone()
    }

    fn handle_message(&self,
                      registry: &ActorRegistry,
                      msg_type: &str,
                      msg: &json::Object,
                      stream: &mut TcpStream) -> Result<ActorMessageStatus, ()> {
        Ok(match msg_type {
            "start" => {
                **self.is_recording.lock().as_mut().unwrap() = true;

                let (tx, rx) = ipc::channel::<TimelineMarker>().unwrap();
                self.script_sender.send(SetTimelineMarkers(self.pipeline,
                                                           self.marker_types.clone(),
                                                           tx)).unwrap();

                *self.stream.borrow_mut() = stream.try_clone().ok();

                // init memory actor
                if let Some(with_memory) = msg.get("withMemory") {
                    if let Some(true) = with_memory.as_boolean() {
                        *self.memory_actor.borrow_mut() = Some(MemoryActor::create(registry));
                    }
                }

                // init framerate actor
                if let Some(with_ticks) = msg.get("withTicks") {
                    if let Some(true) = with_ticks.as_boolean() {
                        let framerate_actor = Some(FramerateActor::create(
                                registry,
                                self.pipeline.clone(),
                                self.script_sender.clone()));
                        *self.framerate_actor.borrow_mut() = framerate_actor;
                    }
                }

                let emitter = Emitter::new(self.name(), registry.get_shareable(),
                                           registry.start_stamp(),
                                           stream.try_clone().unwrap(),
                                           self.memory_actor.borrow().clone(),
                                           self.framerate_actor.borrow().clone());

                self.pull_timeline_data(rx, emitter);

                let msg = StartReply {
                    from: self.name(),
                    value: HighResolutionStamp::new(registry.start_stamp(), PreciseTime::now()),
                };
                stream.write_json_packet(&msg);
                ActorMessageStatus::Processed
            }

            "stop" => {
                let msg = StopReply {
                    from: self.name(),
                    value: HighResolutionStamp::new(registry.start_stamp(), PreciseTime::now()),
                };

                stream.write_json_packet(&msg);
                self.script_sender.send(DropTimelineMarkers(self.pipeline, self.marker_types.clone())).unwrap();

                if let Some(ref actor_name) = *self.framerate_actor.borrow() {
                    registry.drop_actor_later(actor_name.clone());
                }

                if let Some(ref actor_name) = *self.memory_actor.borrow() {
                    registry.drop_actor_later(actor_name.clone());
                }

                **self.is_recording.lock().as_mut().unwrap() = false;
                self.stream.borrow_mut().take();
                ActorMessageStatus::Processed
            }

            "isRecording" => {
                let msg = IsRecordingReply {
                    from: self.name(),
                    value: self.is_recording.lock().unwrap().clone()
                };

                stream.write_json_packet(&msg);
                ActorMessageStatus::Processed
            }

            _ => {
                ActorMessageStatus::Ignored
            }
        })
    }
}

impl Emitter {
    pub fn new(name: String,
               registry: Arc<Mutex<ActorRegistry>>,
               start_stamp: PreciseTime,
               stream: TcpStream,
               memory_actor_name: Option<String>,
               framerate_actor_name: Option<String>) -> Emitter {

        Emitter {
            from: name,
            stream: stream,
            markers: Vec::new(),
            registry: registry,
            start_stamp: start_stamp,

            framerate_actor: framerate_actor_name,
            memory_actor: memory_actor_name,
        }
    }

    fn add_marker(&mut self, start_payload: TimelineMarker, end_payload: TimelineMarker) -> () {
        self.markers.push(TimelineMarkerReply {
            name: start_payload.name,
            start: HighResolutionStamp::new(self.start_stamp, start_payload.time),
            end: HighResolutionStamp::new(self.start_stamp, end_payload.time),
            stack: start_payload.stack,
            endStack: end_payload.stack,
        });
    }

    fn send(&mut self) -> () {
        let end_time = PreciseTime::now();
        let reply = MarkersEmitterReply {
            __type__: "markers".to_string(),
            markers: mem::replace(&mut self.markers, Vec::new()),
            from: self.from.clone(),
            endTime: HighResolutionStamp::new(self.start_stamp, end_time),
        };
        self.stream.write_json_packet(&reply);

        if let Some(ref actor_name) = self.framerate_actor {
            let mut lock = self.registry.lock();
            let registry = lock.as_mut().unwrap();
            let framerate_actor = registry.find_mut::<FramerateActor>(actor_name);
            let framerateReply = FramerateEmitterReply {
                __type__: "framerate".to_string(),
                from: framerate_actor.name(),
                delta: HighResolutionStamp::new(self.start_stamp, end_time),
                timestamps: framerate_actor.take_pending_ticks(),
            };
            self.stream.write_json_packet(&framerateReply);
        }

        if let Some(ref actor_name) = self.memory_actor {
            let registry = self.registry.lock().unwrap();
            let memory_actor = registry.find::<MemoryActor>(actor_name);
            let memoryReply = MemoryEmitterReply {
                __type__: "memory".to_string(),
                from: memory_actor.name(),
                delta: HighResolutionStamp::new(self.start_stamp, end_time),
                measurement: memory_actor.measure(),
            };
            self.stream.write_json_packet(&memoryReply);
        }
    }
}
<commit_msg>Remove Emitter::markers.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
use msg::constellation_msg::PipelineId;
use rustc_serialize::{json, Encoder, Encodable};
use std::cell::RefCell;
use std::collections::{HashMap, VecDeque};
use std::net::TcpStream;
use std::sync::mpsc::channel;
use std::sync::{Arc, Mutex};
use std::thread::sleep_ms;

use actor::{Actor, ActorRegistry, ActorMessageStatus};
use actors::framerate::FramerateActor;
use actors::memory::{MemoryActor, TimelineMemoryReply};
use devtools_traits::DevtoolScriptControlMsg;
use devtools_traits::DevtoolScriptControlMsg::{SetTimelineMarkers, DropTimelineMarkers};
use devtools_traits::{PreciseTime, TimelineMarker, TracingMetadata, TimelineMarkerType};
use protocol::JsonPacketStream;
use util::task;

pub struct TimelineActor {
    name: String,
    script_sender: IpcSender<DevtoolScriptControlMsg>,
    marker_types: Vec<TimelineMarkerType>,
    pipeline: PipelineId,
    is_recording: Arc<Mutex<bool>>,
    stream: RefCell<Option<TcpStream>>,

    framerate_actor: RefCell<Option<String>>,
    memory_actor: RefCell<Option<String>>,
}

struct Emitter {
    from: String,
    stream: TcpStream,
    registry: Arc<Mutex<ActorRegistry>>,
    start_stamp: PreciseTime,

    framerate_actor: Option<String>,
    memory_actor: Option<String>,
}

#[derive(RustcEncodable)]
struct IsRecordingReply {
    from: String,
    value: bool
}

#[derive(RustcEncodable)]
struct StartReply {
    from: String,
    value: HighResolutionStamp,
}

#[derive(RustcEncodable)]
struct StopReply {
    from: String,
    value: HighResolutionStamp,
}

#[derive(RustcEncodable)]
struct TimelineMarkerReply {
    name: String,
    start: HighResolutionStamp,
    end: HighResolutionStamp,
    stack: Option<Vec<()>>,
    endStack: Option<Vec<()>>,
}

#[derive(RustcEncodable)]
struct MarkersEmitterReply {
    __type__: String,
    markers: Vec<TimelineMarkerReply>,
    from: String,
    endTime: HighResolutionStamp,
}

#[derive(RustcEncodable)]
struct MemoryEmitterReply {
    __type__: String,
    from: String,
    delta: HighResolutionStamp,
    measurement: TimelineMemoryReply,
}

#[derive(RustcEncodable)]
struct FramerateEmitterReply {
    __type__: String,
    from: String,
    delta: HighResolutionStamp,
    timestamps: Vec<HighResolutionStamp>,
}

/// HighResolutionStamp is struct that contains duration in milliseconds
/// with accuracy to microsecond that shows how much time has passed since
/// actor registry inited
/// analog https://w3c.github.io/hr-time/#sec-DOMHighResTimeStamp
pub struct HighResolutionStamp(f64);

impl HighResolutionStamp {
    pub fn new(start_stamp: PreciseTime, time: PreciseTime) -> HighResolutionStamp {
        let duration = start_stamp.to(time).num_microseconds()
                                  .expect("Too big duration in microseconds");
        HighResolutionStamp(duration as f64 / 1000 as f64)
    }

    pub fn wrap(time: f64) -> HighResolutionStamp {
        HighResolutionStamp(time)
    }
}

impl Encodable for HighResolutionStamp {
    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        self.0.encode(s)
    }
}

static DEFAULT_TIMELINE_DATA_PULL_TIMEOUT: u32 = 200; //ms

impl TimelineActor {
    pub fn new(name: String,
               pipeline: PipelineId,
               script_sender: IpcSender<DevtoolScriptControlMsg>) -> TimelineActor {

        let marker_types = vec!(TimelineMarkerType::Reflow,
                                TimelineMarkerType::DOMEvent);

        TimelineActor {
            name: name,
            pipeline: pipeline,
            marker_types: marker_types,
            script_sender: script_sender,
            is_recording: Arc::new(Mutex::new(false)),
            stream: RefCell::new(None),

            framerate_actor: RefCell::new(None),
            memory_actor: RefCell::new(None),
        }
    }

    fn pull_timeline_data(&self, receiver: IpcReceiver<TimelineMarker>, mut emitter: Emitter) {
        let is_recording = self.is_recording.clone();

        if !*is_recording.lock().unwrap() {
            return;
        }

        /// Select root(with depth 0) TimelineMarker pair (IntervalStart + IntervalEnd)
        /// from queue and add marker to emitter
        /// Return true if closed (IntervalStart + IntervalEnd) pair was founded
        fn group(queue: &mut VecDeque<TimelineMarker>, depth: usize,
                 start_payload: Option<TimelineMarker>, emitter: &Emitter,
                 markers: &mut Vec<TimelineMarkerReply>) -> bool {

            if let Some(start_payload) = start_payload {
                if start_payload.metadata != TracingMetadata::IntervalStart {
                    panic!("Start payload doesn't have metadata IntervalStart");
                }

                if let Some(end_payload) = queue.pop_front() {
                    match end_payload.metadata {
                        TracingMetadata::IntervalEnd => {
                            if depth == 0 {
                                // Emit TimelineMarkerReply, pair was found
                                markers.push(emitter.marker(start_payload, end_payload));
                            }
                            return true;
                        }
                        TracingMetadata::IntervalStart => {
                            if group(queue, depth + 1, Some(end_payload), emitter, markers) {
                                return group(queue, depth, Some(start_payload), emitter, markers);
                            } else {
                                queue.push_front(start_payload);
                            }
                        }
                        _ => panic!("Unknown tracingMetadata")
                    }
                } else {
                    queue.push_front(start_payload);
                }
            }

            false
        }

        task::spawn_named("PullTimelineMarkers".to_string(), move || {
            let mut queues = HashMap::new();
            queues.insert("Reflow".to_string(), VecDeque::new());
            queues.insert("DOMEvent".to_string(), VecDeque::new());

            loop {
                if !*is_recording.lock().unwrap() {
                    break;
                }

                // Creating queues by marker.name
                loop {
                    match receiver.try_recv() {
                        Ok(marker) => {
                            if let Some(list) = queues.get_mut(&marker.name) {
                                list.push_back(marker);
                            }
                        }

                        Err(_) => break
                    }
                }

                // Emit all markers
                let mut markers = vec![];
                for (_, queue) in &mut queues {
                    let start_payload = queue.pop_front();
                    group(queue, 0, start_payload, &emitter, &mut markers);
                }
                emitter.send(markers);

                sleep_ms(DEFAULT_TIMELINE_DATA_PULL_TIMEOUT);
            }
        });
    }
}

impl Actor for TimelineActor {
    fn name(&self) -> String {
        self.name.clone()
    }

    fn handle_message(&self,
                      registry: &ActorRegistry,
                      msg_type: &str,
                      msg: &json::Object,
                      stream: &mut TcpStream) -> Result<ActorMessageStatus, ()> {
        Ok(match msg_type {
            "start" => {
                **self.is_recording.lock().as_mut().unwrap() = true;

                let (tx, rx) = ipc::channel::<TimelineMarker>().unwrap();
                self.script_sender.send(SetTimelineMarkers(self.pipeline,
                                                           self.marker_types.clone(),
                                                           tx)).unwrap();

                *self.stream.borrow_mut() = stream.try_clone().ok();

                // init memory actor
                if let Some(with_memory) = msg.get("withMemory") {
                    if let Some(true) = with_memory.as_boolean() {
                        *self.memory_actor.borrow_mut() = Some(MemoryActor::create(registry));
                    }
                }

                // init framerate actor
                if let Some(with_ticks) = msg.get("withTicks") {
                    if let Some(true) = with_ticks.as_boolean() {
                        let framerate_actor = Some(FramerateActor::create(
                                registry,
                                self.pipeline.clone(),
                                self.script_sender.clone()));
                        *self.framerate_actor.borrow_mut() = framerate_actor;
                    }
                }

                let emitter = Emitter::new(self.name(), registry.get_shareable(),
                                           registry.start_stamp(),
                                           stream.try_clone().unwrap(),
                                           self.memory_actor.borrow().clone(),
                                           self.framerate_actor.borrow().clone());

                self.pull_timeline_data(rx, emitter);

                let msg = StartReply {
                    from: self.name(),
                    value: HighResolutionStamp::new(registry.start_stamp(), PreciseTime::now()),
                };
                stream.write_json_packet(&msg);
                ActorMessageStatus::Processed
            }

            "stop" => {
                let msg = StopReply {
                    from: self.name(),
                    value: HighResolutionStamp::new(registry.start_stamp(), PreciseTime::now()),
                };

                stream.write_json_packet(&msg);
                self.script_sender.send(DropTimelineMarkers(self.pipeline, self.marker_types.clone())).unwrap();

                if let Some(ref actor_name) = *self.framerate_actor.borrow() {
                    registry.drop_actor_later(actor_name.clone());
                }

                if let Some(ref actor_name) = *self.memory_actor.borrow() {
                    registry.drop_actor_later(actor_name.clone());
                }

                **self.is_recording.lock().as_mut().unwrap() = false;
                self.stream.borrow_mut().take();
                ActorMessageStatus::Processed
            }

            "isRecording" => {
                let msg = IsRecordingReply {
                    from: self.name(),
                    value: self.is_recording.lock().unwrap().clone()
                };

                stream.write_json_packet(&msg);
                ActorMessageStatus::Processed
            }

            _ => {
                ActorMessageStatus::Ignored
            }
        })
    }
}

impl Emitter {
    pub fn new(name: String,
               registry: Arc<Mutex<ActorRegistry>>,
               start_stamp: PreciseTime,
               stream: TcpStream,
               memory_actor_name: Option<String>,
               framerate_actor_name: Option<String>) -> Emitter {

        Emitter {
            from: name,
            stream: stream,
            registry: registry,
            start_stamp: start_stamp,

            framerate_actor: framerate_actor_name,
            memory_actor: memory_actor_name,
        }
    }

    fn marker(&self, start_payload: TimelineMarker, end_payload: TimelineMarker)
              -> TimelineMarkerReply {
        TimelineMarkerReply {
            name: start_payload.name,
            start: HighResolutionStamp::new(self.start_stamp, start_payload.time),
            end: HighResolutionStamp::new(self.start_stamp, end_payload.time),
            stack: start_payload.stack,
            endStack: end_payload.stack,
        }
    }

    fn send(&mut self, markers: Vec<TimelineMarkerReply>) -> () {
        let end_time = PreciseTime::now();
        let reply = MarkersEmitterReply {
            __type__: "markers".to_string(),
            markers: markers,
            from: self.from.clone(),
            endTime: HighResolutionStamp::new(self.start_stamp, end_time),
        };
        self.stream.write_json_packet(&reply);

        if let Some(ref actor_name) = self.framerate_actor {
            let mut lock = self.registry.lock();
            let registry = lock.as_mut().unwrap();
            let framerate_actor = registry.find_mut::<FramerateActor>(actor_name);
            let framerateReply = FramerateEmitterReply {
                __type__: "framerate".to_string(),
                from: framerate_actor.name(),
                delta: HighResolutionStamp::new(self.start_stamp, end_time),
                timestamps: framerate_actor.take_pending_ticks(),
            };
            self.stream.write_json_packet(&framerateReply);
        }

        if let Some(ref actor_name) = self.memory_actor {
            let registry = self.registry.lock().unwrap();
            let memory_actor = registry.find::<MemoryActor>(actor_name);
            let memoryReply = MemoryEmitterReply {
                __type__: "memory".to_string(),
                from: memory_actor.name(),
                delta: HighResolutionStamp::new(self.start_stamp, end_time),
                measurement: memory_actor.measure(),
            };
            self.stream.write_json_packet(&memoryReply);
        }
    }
}
<|endoftext|>


<commit_before>use libc::{c_int, c_double, c_char, c_void};
use std::ffi::CStr;
use std::mem;

pub type EnergyMonInitFn = unsafe extern fn(em: *mut EnergyMon) -> c_int;
pub type EnergyMonReadTotalFn = unsafe extern fn(em: *mut EnergyMon) -> c_double;
pub type EnergyMonFinishFn = unsafe extern fn(em: *mut EnergyMon) -> c_int;
pub type EnergyMonGetSourceFn = unsafe extern fn(*mut c_char) -> *mut c_char;

#[repr(C)]
pub struct EnergyMon {
    pub finit: EnergyMonInitFn,
    pub fread: EnergyMonReadTotalFn,
    pub ffinish: EnergyMonFinishFn,
    pub fsource: EnergyMonGetSourceFn,
    pub state: *mut c_void,
}

extern {
    fn em_impl_get(em: *mut EnergyMon) -> c_int;
}

impl EnergyMon {
    pub fn new() -> Result<EnergyMon, String> {
        unsafe {
            let mut em: EnergyMon = mem::uninitialized();
            let result = em_impl_get(&mut em);
            if result != 0 {
                return Err("Failed to initialize energymon".to_string());
            }
            Ok(em)
        }
    }

    pub fn init(&mut self) -> Result<(), String> {
        let result: i32 = unsafe {
            (self.finit)(self)
        };
        if result != 0 {
            return Err("Failed to initialize energymon".to_string());
        }
        Ok(())
    }

    pub fn read(&mut self) -> f64 {
        unsafe {
            (self.fread)(self)
        }

    }

    pub fn finish(&mut self) -> Result<(), String> {
        let result: i32 = unsafe {
            (self.ffinish)(self)
        };
        if result != 0 {
            return Err("Failed to initialize energymon".to_string());
        }
        Ok(())
    }

    pub fn source(&mut self) -> Result<String, String> {
        let mut buf = [0; 100];
        unsafe {
            let ret = (self.fsource)(buf.as_mut_ptr());
            if ret.is_null() {
                return Err("Failed to get energymon source".to_string());
            }
            Ok(String::from_utf8_lossy(CStr::from_ptr(ret).to_bytes()).into_owned())
        }
    }
}

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

    #[test]
    fn test_interface() {
        let mut em: EnergyMon = EnergyMon::new().unwrap();
        em.init().unwrap();
        let val = em.read();
        assert!(val >= 0.0);
        let source = em.source().unwrap();
        em.finish().unwrap();
        println!("Read {} from {}", val, source);
    }

}
<commit_msg>Different string handling<commit_after>use libc::{c_int, c_double, c_char, c_void};
use std::mem;

pub type EnergyMonInitFn = unsafe extern fn(em: *mut EnergyMon) -> c_int;
pub type EnergyMonReadTotalFn = unsafe extern fn(em: *mut EnergyMon) -> c_double;
pub type EnergyMonFinishFn = unsafe extern fn(em: *mut EnergyMon) -> c_int;
pub type EnergyMonGetSourceFn = unsafe extern fn(*mut c_char) -> *mut c_char;

#[repr(C)]
pub struct EnergyMon {
    pub finit: EnergyMonInitFn,
    pub fread: EnergyMonReadTotalFn,
    pub ffinish: EnergyMonFinishFn,
    pub fsource: EnergyMonGetSourceFn,
    pub state: *mut c_void,
}

extern {
    fn em_impl_get(em: *mut EnergyMon) -> c_int;
}

impl EnergyMon {
    pub fn new() -> Result<EnergyMon, String> {
        unsafe {
            let mut em: EnergyMon = mem::uninitialized();
            let result = em_impl_get(&mut em);
            if result != 0 {
                return Err("Failed to initialize energymon".to_string());
            }
            Ok(em)
        }
    }

    pub fn init(&mut self) -> Result<(), String> {
        let result: i32 = unsafe {
            (self.finit)(self)
        };
        if result != 0 {
            return Err("Failed to initialize energymon".to_string());
        }
        Ok(())
    }

    pub fn read(&mut self) -> f64 {
        unsafe {
            (self.fread)(self)
        }

    }

    pub fn finish(&mut self) -> Result<(), String> {
        let result: i32 = unsafe {
            (self.ffinish)(self)
        };
        if result != 0 {
            return Err("Failed to initialize energymon".to_string());
        }
        Ok(())
    }

    pub fn source(&mut self) -> Result<String, String> {
        let mut buf = [0; 100];
        unsafe {
            let ret = (self.fsource)(buf.as_mut_ptr());
            if ret.is_null() {
                return Err("Failed to get energymon source".to_string());
            }
            let buf = mem::transmute::<&[c_char], &[u8]>(&buf);
            Ok(String::from_utf8_lossy(buf).into_owned())
        }
    }
}

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

    #[test]
    fn test_interface() {
        let mut em: EnergyMon = EnergyMon::new().unwrap();
        em.init().unwrap();
        let val = em.read();
        assert!(val >= 0.0);
        let source = em.source().unwrap();
        em.finish().unwrap();
        println!("Read {} from {}", val, source);
    }

}
<|endoftext|>