<commit_before>use detail::{align_down, mut_offset};
use reg_context::InitFn;
use stack::Stack;

#[cfg(not(nightly))]
#[link(name = "asm", kind = "static")]
extern "C" {
    pub fn bootstrap_green_task();
    pub fn prefetch(data: *const usize);
    pub fn swap_registers(out_regs: *mut Registers, in_regs: *const Registers);
}

#[cfg(nightly)]
mod asm {
    use super::Registers;
    /// prefetch data
    #[inline]
    pub unsafe extern "C" fn prefetch(data: *const usize) {
        asm!("
        prefetcht1 $0
        "
        : // no output
        : "m"(*data)
        :
        : "volatile");
    }
    #[inline(never)]
    #[naked]
    pub unsafe extern "C" fn bootstrap_green_task() {
        asm!("
        mov %r12, %rdi     // setup the function arg
        mov %r13, %rsi     // setup the function arg
        mov %r14, 8(%rsp)  // this is the new return adrress
        "
        : // no output
        : // no input
        : "memory"
        : "volatile");
    }
    #[inline(never)]
    pub unsafe extern "C" fn swap_registers(out_regs: *mut Registers, in_regs: *const Registers) {
        // The first argument is in %rdi, and the second one is in %rsi
        asm!(
            ""
            :
            : "{rcx}"(out_regs), "{rdx}"(in_regs)
            :
            :
        );

        // introduce this function to workaround rustc bug! (#6)
        // the naked function is not correct any more
        #[naked]
        unsafe extern "C" fn _swap_reg() {
            // Save registers
            asm!("
        mov %rbx, (0*8)(%rdi)
        mov %rsp, (1*8)(%rdi)
        mov %rbp, (2*8)(%rdi)
        mov %r12, (4*8)(%rdi)
        mov %r13, (5*8)(%rdi)
        mov %r14, (6*8)(%rdi)
        mov %r15, (7*8)(%rdi)

        mov %rdi, (3*8)(%rdi)

        mov (0*8)(%rsi), %rbx
        mov (1*8)(%rsi), %rsp
        mov (2*8)(%rsi), %rbp
        mov (4*8)(%rsi), %r12
        mov (5*8)(%rsi), %r13
        mov (6*8)(%rsi), %r14
        mov (7*8)(%rsi), %r15

        mov (3*8)(%rsi), %rdi
        "
        :
        : //"{rdi}"(out_regs), "{rsi}"(in_regs)
        : "memory"
        : "volatile");
        }
        _swap_reg()
    }
}
#[cfg(nightly)]
pub use self::asm::*;

#[repr(C)]
#[derive(Debug)]
pub struct Registers {
    gpr: [usize; 8],
}

impl Registers {
    pub fn new() -> Registers {
        Registers { gpr: [0; 8] }
    }

    #[inline]
    pub fn prefetch(&self) {
        unsafe {
            prefetch(self as *const _ as *const usize);
            prefetch(self.gpr[1] as *const usize);
        }
    }
}

pub fn initialize_call_frame(
    regs: &mut Registers,
    fptr: InitFn,
    arg: usize,
    arg2: *mut usize,
    stack: &Stack,
) {
    // Redefinitions from rt/arch/x86_64/regs.h
    const RUSTRT_RSP: usize = 1;
    const RUSTRT_RBP: usize = 2;
    const RUSTRT_R12: usize = 4;
    const RUSTRT_R13: usize = 5;
    const RUSTRT_R14: usize = 6;

    let sp = align_down(stack.end());

    // These registers are frobbed by rust_bootstrap_green_task into the right
    // location so we can invoke the "real init function", `fptr`.
    regs.gpr[RUSTRT_R12] = arg;
    regs.gpr[RUSTRT_R13] = arg2 as usize;
    regs.gpr[RUSTRT_R14] = fptr as usize;

    // These registers are picked up by the regular context switch paths. These
    // will put us in "mostly the right context" except for frobbing all the
    // arguments to the right place. We have the small trampoline code inside of
    // rust_bootstrap_green_task to do that.
    regs.gpr[RUSTRT_RSP] = mut_offset(sp, -4) as usize;

    // setup the init stack
    // this is prepared for the swap context
    // different platform/debug has different offset between sp and ret
    unsafe {
        *mut_offset(sp, -4) = bootstrap_green_task as usize;
        *mut_offset(sp, -3) = bootstrap_green_task as usize;
        // leave enough space for RET
        *mut_offset(sp, -2) = 0;
        *mut_offset(sp, -1) = 0;
    }

    // Last base pointer on the stack should be 0
    regs.gpr[RUSTRT_RBP] = 0;
}
<commit_msg>:bug: fix unix nighlty swap_register<commit_after>use detail::{align_down, mut_offset};
use reg_context::InitFn;
use stack::Stack;

#[cfg(not(nightly))]
#[link(name = "asm", kind = "static")]
extern "C" {
    pub fn bootstrap_green_task();
    pub fn prefetch(data: *const usize);
    pub fn swap_registers(out_regs: *mut Registers, in_regs: *const Registers);
}

#[cfg(nightly)]
mod asm {
    use super::Registers;
    /// prefetch data
    #[inline]
    pub unsafe extern "C" fn prefetch(data: *const usize) {
        asm!("
        prefetcht1 $0
        "
        : // no output
        : "m"(*data)
        :
        : "volatile");
    }
    #[inline(never)]
    #[naked]
    pub unsafe extern "C" fn bootstrap_green_task() {
        asm!("
        mov %r12, %rdi     // setup the function arg
        mov %r13, %rsi     // setup the function arg
        mov %r14, 8(%rsp)  // this is the new return adrress
        "
        : // no output
        : // no input
        : "memory"
        : "volatile");
    }
    #[inline(never)]
    pub unsafe extern "C" fn swap_registers(out_regs: *mut Registers, in_regs: *const Registers) {
        // The first argument is in %rdi, and the second one is in %rsi
        asm!(
            ""
            :
            : "{rdi}"(out_regs), "{rsi}"(in_regs)
            :
            :
        );

        // introduce this function to workaround rustc bug! (#6)
        // the naked function is not correct any more
        #[naked]
        unsafe extern "C" fn _swap_reg() {
            // Save registers
            asm!("
        mov %rbx, (0*8)(%rdi)
        mov %rsp, (1*8)(%rdi)
        mov %rbp, (2*8)(%rdi)
        mov %r12, (4*8)(%rdi)
        mov %r13, (5*8)(%rdi)
        mov %r14, (6*8)(%rdi)
        mov %r15, (7*8)(%rdi)

        mov %rdi, (3*8)(%rdi)

        mov (0*8)(%rsi), %rbx
        mov (1*8)(%rsi), %rsp
        mov (2*8)(%rsi), %rbp
        mov (4*8)(%rsi), %r12
        mov (5*8)(%rsi), %r13
        mov (6*8)(%rsi), %r14
        mov (7*8)(%rsi), %r15

        mov (3*8)(%rsi), %rdi
        "
        :
        : //"{rdi}"(out_regs), "{rsi}"(in_regs)
        : "memory"
        : "volatile");
        }
        _swap_reg()
    }
}
#[cfg(nightly)]
pub use self::asm::*;

#[repr(C)]
#[derive(Debug)]
pub struct Registers {
    gpr: [usize; 8],
}

impl Registers {
    pub fn new() -> Registers {
        Registers { gpr: [0; 8] }
    }

    #[inline]
    pub fn prefetch(&self) {
        unsafe {
            prefetch(self as *const _ as *const usize);
            prefetch(self.gpr[1] as *const usize);
        }
    }
}

pub fn initialize_call_frame(
    regs: &mut Registers,
    fptr: InitFn,
    arg: usize,
    arg2: *mut usize,
    stack: &Stack,
) {
    // Redefinitions from rt/arch/x86_64/regs.h
    const RUSTRT_RSP: usize = 1;
    const RUSTRT_RBP: usize = 2;
    const RUSTRT_R12: usize = 4;
    const RUSTRT_R13: usize = 5;
    const RUSTRT_R14: usize = 6;

    let sp = align_down(stack.end());

    // These registers are frobbed by rust_bootstrap_green_task into the right
    // location so we can invoke the "real init function", `fptr`.
    regs.gpr[RUSTRT_R12] = arg;
    regs.gpr[RUSTRT_R13] = arg2 as usize;
    regs.gpr[RUSTRT_R14] = fptr as usize;

    // These registers are picked up by the regular context switch paths. These
    // will put us in "mostly the right context" except for frobbing all the
    // arguments to the right place. We have the small trampoline code inside of
    // rust_bootstrap_green_task to do that.
    regs.gpr[RUSTRT_RSP] = mut_offset(sp, -4) as usize;

    // setup the init stack
    // this is prepared for the swap context
    // different platform/debug has different offset between sp and ret
    unsafe {
        *mut_offset(sp, -4) = bootstrap_green_task as usize;
        *mut_offset(sp, -3) = bootstrap_green_task as usize;
        // leave enough space for RET
        *mut_offset(sp, -2) = 0;
        *mut_offset(sp, -1) = 0;
    }

    // Last base pointer on the stack should be 0
    regs.gpr[RUSTRT_RBP] = 0;
}
<|endoftext|>


<commit_before>use query::Scorer;
use DocId;
use postings::DocSet;

pub struct BooleanScorer {
}

impl DocSet for BooleanScorer {
    fn advance(&mut self,) -> bool {
        panic!("a");
    }

    fn doc(&self,) -> DocId {
        panic!("a");
    }
}

impl Scorer for BooleanScorer {

    fn score(&self,) -> f32 {
        panic!("");
    }
}<commit_msg>issue/50    Implementation ooleanScorer.<commit_after>use query::Scorer;
use DocId;
use Score;
use std::collections::BinaryHeap;
use std::cmp::Ordering;
use postings::DocSet;
use query::OccurFilter;

struct ScoreCombiner {
    coords: Vec<Score>,
    num_fields: usize,
    score: Score,
}

impl ScoreCombiner {

    fn update(&mut self, score: Score) {
        self.score += score;
        self.num_fields += 1;
    }

    fn clear(&mut self,) {
        self.score = 0f32;
        self.num_fields = 0;
    }

    /// Compute the coord term
    fn coord(&self,) -> f32 {
        self.coords[self.num_fields]
    }

    #[inline]
    fn score(&self, ) -> Score {
        self.score * self.coord()
    }
}

impl From<Vec<Score>> for ScoreCombiner {
    fn from(coords: Vec<Score>) -> ScoreCombiner {
        ScoreCombiner {
            coords: coords,
            num_fields: 0,
            score: 0f32,
        }
    }
}

/// Each `HeapItem` represents the head of
/// a segment postings being merged.
///
/// * `doc` - is the current doc id for the given segment postings
/// * `ord` - is the ordinal used to identify to which segment postings
/// this heap item belong to.
#[derive(Eq, PartialEq)]
struct HeapItem {
    doc: DocId,
    ord: u32,
}

/// `HeapItem` are ordered by the document
impl PartialOrd for HeapItem {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for HeapItem {
    fn cmp(&self, other:&Self) -> Ordering {
         (other.doc).cmp(&self.doc)
    }
}

pub struct BooleanScorer<TScorer: Scorer> {
    postings: Vec<TScorer>,
    queue: BinaryHeap<HeapItem>,
    doc: DocId,
    score_combiner: ScoreCombiner,
    filter: OccurFilter,
}

impl<TScorer: Scorer> BooleanScorer<TScorer> {

    fn new(postings: Vec<TScorer>, filter: OccurFilter) -> BooleanScorer<TScorer> {
        let num_postings = postings.len();
        let query_coords: Vec<Score> = (0..num_postings + 1)
            .map(|i| (i as Score) / (num_postings as Score))
            .collect();
        let score_combiner = ScoreCombiner::from(query_coords);
        let heap_items: Vec<HeapItem> = postings
            .iter()
            .map(|posting| posting.doc())
            .enumerate()
            .map(|(ord, doc)| {
                HeapItem {
                    doc: doc,
                    ord: ord as u32
                }
            })
            .collect();
        BooleanScorer {
            postings: postings,
            queue: BinaryHeap::from(heap_items),
            doc: 0u32,
            score_combiner: score_combiner,
            filter: filter,

        }
    }

    /// Advances the head of our heap (the segment postings with the lowest doc)
    /// It will also update the new current `DocId` as well as the term frequency
    /// associated with the segment postings.
    ///
    /// After advancing the `SegmentPosting`, the postings is removed from the heap
    /// if it has been entirely consumed, or pushed back into the heap.
    ///
    /// # Panics
    /// This method will panic if the head `SegmentPostings` is not empty.
    fn advance_head(&mut self,) {
        {
            let mut mutable_head = self.queue.peek_mut().unwrap();
            let cur_postings = &mut self.postings[mutable_head.ord as usize];
            if cur_postings.advance() {
                mutable_head.doc = cur_postings.doc();
                return;
            }

        }
        self.queue.pop();
    }
}

impl<TScorer: Scorer> DocSet for BooleanScorer<TScorer> {
    fn advance(&mut self,) -> bool {
        loop {
            self.score_combiner.clear();
            let mut ord_bitset = 0u64;
            match self.queue.peek() {
                Some(heap_item) => {
                    let ord = heap_item.ord as usize;
                    self.doc = heap_item.doc;
                    let score = self.postings[ord].score();
                    self.score_combiner.update(score);
                    ord_bitset |= 1 << ord;
                }
                None => {
                    return false;
                }
            }
            self.advance_head();
            while let Some(&HeapItem {doc, ord}) = self.queue.peek() {
                if doc == self.doc {
                    let ord = ord as usize;
                    let score = self.postings[ord].score();
                    self.score_combiner.update(score);
                    ord_bitset |= 1 << ord;
                }
                else  {
                    break;
                }
                self.advance_head();
            }
            if self.filter.accept(ord_bitset) {
                return true;
            }
        }
    }

    fn doc(&self,) -> DocId {
        panic!("a");
    }
}

impl<TScorer: Scorer> Scorer for BooleanScorer<TScorer> {

    fn score(&self,) -> f32 {
        panic!("");
    }
}

<|endoftext|>


<commit_before>use std::collections::{HashMap, HashSet};
use std::sync::Arc;
use parking_lot::{RwLock};
use bifrost_hasher::{hash_str, hash_bytes};
use raft::{RaftService, IS_LEADER};
use rpc;
use utils::bincode;
use serde;
use super::super::{OpType};
use super::super::super::RaftMsg;
use super::*;

pub struct Subscriber {
    pub session_id: u64,
    pub client: Arc<AsyncServiceClient>
}

pub struct Subscriptions {
    next_id: u64,
    subscribers: HashMap<u64, Subscriber>,
    suber_subs: HashMap<u64, HashSet<u64>>, //suber_id -> sub_id
    subscriptions: HashMap<SubKey, HashSet<u64>>, // key -> sub_id
    sub_suber: HashMap<u64, u64>,
    sub_to_key: HashMap<u64, SubKey>, //sub_id -> sub_key
}

impl Subscriptions {

    pub fn new() -> Subscriptions {
        Subscriptions {
            next_id: 0,
            subscribers: HashMap::new(),
            suber_subs: HashMap::new(),
            subscriptions: HashMap::new(),
            sub_suber: HashMap::new(),
            sub_to_key: HashMap::new(),
        }
    }

    pub fn subscribe(&mut self, key: SubKey, address: &String, session_id: u64) -> Result<u64, ()> {
        let sub_service_id = DEFAULT_SERVICE_ID;
        let suber_id = hash_str(address);
        let suber_exists = self.subscribers.contains_key(&suber_id);
        let sub_id = self.next_id;
        let require_reload_suber = if suber_exists {
            let suber_session_id = self.subscribers.get(&suber_id).unwrap().session_id;
            let session_match = (suber_session_id == session_id);
            if !session_match {
                self.remove_subscriber(suber_id);
                true
            } else {false}
        } else {true};
        if !self.subscribers.contains_key(&suber_id) {
            self.subscribers.insert(suber_id, Subscriber {
                session_id: session_id,
                client: {
                    if let Ok(client) = rpc::DEFAULT_CLIENT_POOL.get(address) {
                        AsyncServiceClient::new(sub_service_id, &client)
                    } else {
                        return Err(());
                    }
                }
            });
        }
        self.suber_subs.entry(suber_id).or_insert_with(|| HashSet::new()).insert(sub_id);
        self.subscriptions.entry(key).or_insert_with(|| HashSet::new()).insert(sub_id);
        self.sub_to_key.insert(sub_id, key);
        self.sub_suber.insert(sub_id, suber_id);

        self.next_id += 1;
        Ok(sub_id)
    }

    pub fn remove_subscriber(&mut self, suber_id: u64) {
        let suber_subs = if let Some(sub_ids) = self.suber_subs.get(&suber_id) {
            sub_ids.iter().cloned().collect()
        } else {Vec::<u64>::new()};
        for subs_id in suber_subs {
            self.remove_subscription(subs_id)
        }
        self.subscribers.remove(&suber_id);
        self.suber_subs.remove(&suber_id);
    }

    pub fn remove_subscription(&mut self, id: u64) {
        let sub_key = self.sub_to_key.remove(&id);
        if let Some(sub_key) = sub_key {
            if let Some(ref mut sub_subers) = self.subscriptions.get_mut(&sub_key) {
                sub_subers.remove(&id);
                self.sub_suber.remove(&id);
            }
        }
    }
}

pub struct SMCallback {
    pub subscriptions: Arc<RwLock<Subscriptions>>,
    pub raft_service: Arc<RaftService>,
    pub sm_id: u64,
}

#[derive(Debug, Clone, Copy)]
pub enum NotifyFailure {
    IsNotLeader,
    OpTypeNotSubscribe,
    CannotFindSubscription,
    CannotFindSubscribers,
    CannotFindSubscriber
}

impl SMCallback {
    pub fn new(state_machine_id: u64, raft_service: Arc<RaftService>) -> SMCallback {
        let meta = raft_service.meta.read();
        let sm = meta.state_machine.read();
        let subs = sm.configs.subscriptions.clone();
        SMCallback {
            subscriptions: subs,
            raft_service: raft_service.clone(),
            sm_id: state_machine_id,
        }
    }

    pub fn notify<R>(&self, func: &RaftMsg<R>, data: R)
        -> Result<(usize, Vec<NotifyFailure>, Vec<Result<Result<(), ()>, rpc::RPCError>>), NotifyFailure>
        where R: serde::Serialize + Send + Sync {
        if !IS_LEADER.get() {return Err(NotifyFailure::IsNotLeader);}
        let (fn_id, op_type, pattern_data) = func.encode();
        match op_type {
            OpType::SUBSCRIBE => {
                let pattern_id = hash_bytes(&pattern_data.as_slice());
                let raft_sid = self.raft_service.options.service_id;
                let sm_id = self.sm_id;
                let key = (raft_sid, sm_id, fn_id, pattern_id);
                let svr_subs = self.subscriptions.read();
                debug!("Subs key: {:?}", svr_subs.subscriptions.keys());
                debug!("Looking for: {:?}", &key);
                if let Some(sub_ids) = svr_subs.subscriptions.get(&key) {
                    let data = bincode::serialize(&data);
                    let sub_result: Vec<_> = sub_ids.iter().map(|sub_id| {
                        if let Some(subscriber_id) = svr_subs.sub_suber.get(&sub_id) {
                            if let Some(subscriber) = svr_subs.subscribers.get(&subscriber_id) {
                                let data = data.clone();
                                let client = subscriber.client.clone();
                                Ok(client.notify(&key, &data))
                            } else {
                                Err(NotifyFailure::CannotFindSubscriber)
                            }
                        } else {
                            Err(NotifyFailure::CannotFindSubscribers)
                        }
                    }).collect();
                    let errors = sub_result.iter()
                        .filter(|r| r.is_err())
                        .map(|r| {if let &Err(e) = r { Some(e) } else { None }})
                        .map(|o| o.clone().unwrap())
                        .collect::<Vec<NotifyFailure>>();
                    let response = sub_result.into_iter()
                        .filter(|r| r.is_ok())
                        .map(|r| r.unwrap())
                        .map(|req| req.wait())
                        .collect::<Vec<_>>();
                    return Ok((sub_ids.len(), errors, response));
                } else {
                    return Err(NotifyFailure::CannotFindSubscription)
                }
            },
            _ => {
                return Err(NotifyFailure::OpTypeNotSubscribe)
            }
        }
    }
}

pub fn notify<R, F>(callback: &Option<SMCallback>, func: &RaftMsg<R>, data: F)
    where F: Fn() -> R,
          R: serde::Serialize + Send + Sync {
    if let Some(ref callback) = *callback {
        callback.notify(func, data());
    }
}<commit_msg>code style optmization<commit_after>use std::collections::{HashMap, HashSet};
use std::sync::Arc;
use parking_lot::{RwLock};
use bifrost_hasher::{hash_str, hash_bytes};
use raft::{RaftService, IS_LEADER};
use rpc;
use utils::bincode;
use serde;
use super::super::{OpType};
use super::super::super::RaftMsg;
use super::*;

pub struct Subscriber {
    pub session_id: u64,
    pub client: Arc<AsyncServiceClient>
}

pub struct Subscriptions {
    next_id: u64,
    subscribers: HashMap<u64, Subscriber>,
    suber_subs: HashMap<u64, HashSet<u64>>, //suber_id -> sub_id
    subscriptions: HashMap<SubKey, HashSet<u64>>, // key -> sub_id
    sub_suber: HashMap<u64, u64>,
    sub_to_key: HashMap<u64, SubKey>, //sub_id -> sub_key
}

impl Subscriptions {

    pub fn new() -> Subscriptions {
        Subscriptions {
            next_id: 0,
            subscribers: HashMap::new(),
            suber_subs: HashMap::new(),
            subscriptions: HashMap::new(),
            sub_suber: HashMap::new(),
            sub_to_key: HashMap::new(),
        }
    }

    pub fn subscribe(&mut self, key: SubKey, address: &String, session_id: u64) -> Result<u64, ()> {
        let sub_service_id = DEFAULT_SERVICE_ID;
        let suber_id = hash_str(address);
        let suber_exists = self.subscribers.contains_key(&suber_id);
        let sub_id = self.next_id;
        let require_reload_suber = if suber_exists {
            let suber_session_id = self.subscribers.get(&suber_id).unwrap().session_id;
            let session_match = suber_session_id == session_id;
            if !session_match {
                self.remove_subscriber(suber_id);
                true
            } else {false}
        } else {true};
        if !self.subscribers.contains_key(&suber_id) {
            self.subscribers.insert(suber_id, Subscriber {
                session_id: session_id,
                client: {
                    if let Ok(client) = rpc::DEFAULT_CLIENT_POOL.get(address) {
                        AsyncServiceClient::new(sub_service_id, &client)
                    } else {
                        return Err(());
                    }
                }
            });
        }
        self.suber_subs.entry(suber_id).or_insert_with(|| HashSet::new()).insert(sub_id);
        self.subscriptions.entry(key).or_insert_with(|| HashSet::new()).insert(sub_id);
        self.sub_to_key.insert(sub_id, key);
        self.sub_suber.insert(sub_id, suber_id);

        self.next_id += 1;
        Ok(sub_id)
    }

    pub fn remove_subscriber(&mut self, suber_id: u64) {
        let suber_subs = if let Some(sub_ids) = self.suber_subs.get(&suber_id) {
            sub_ids.iter().cloned().collect()
        } else {Vec::<u64>::new()};
        for subs_id in suber_subs {
            self.remove_subscription(subs_id)
        }
        self.subscribers.remove(&suber_id);
        self.suber_subs.remove(&suber_id);
    }

    pub fn remove_subscription(&mut self, id: u64) {
        let sub_key = self.sub_to_key.remove(&id);
        if let Some(sub_key) = sub_key {
            if let Some(ref mut sub_subers) = self.subscriptions.get_mut(&sub_key) {
                sub_subers.remove(&id);
                self.sub_suber.remove(&id);
            }
        }
    }
}

pub struct SMCallback {
    pub subscriptions: Arc<RwLock<Subscriptions>>,
    pub raft_service: Arc<RaftService>,
    pub sm_id: u64,
}

#[derive(Debug, Clone, Copy)]
pub enum NotifyFailure {
    IsNotLeader,
    OpTypeNotSubscribe,
    CannotFindSubscription,
    CannotFindSubscribers,
    CannotFindSubscriber
}

impl SMCallback {
    pub fn new(state_machine_id: u64, raft_service: Arc<RaftService>) -> SMCallback {
        let meta = raft_service.meta.read();
        let sm = meta.state_machine.read();
        let subs = sm.configs.subscriptions.clone();
        SMCallback {
            subscriptions: subs,
            raft_service: raft_service.clone(),
            sm_id: state_machine_id,
        }
    }

    pub fn notify<R>(&self, func: &RaftMsg<R>, data: R)
        -> Result<(usize, Vec<NotifyFailure>, Vec<Result<Result<(), ()>, rpc::RPCError>>), NotifyFailure>
        where R: serde::Serialize + Send + Sync {
        if !IS_LEADER.get() {return Err(NotifyFailure::IsNotLeader);}
        let (fn_id, op_type, pattern_data) = func.encode();
        match op_type {
            OpType::SUBSCRIBE => {
                let pattern_id = hash_bytes(&pattern_data.as_slice());
                let raft_sid = self.raft_service.options.service_id;
                let sm_id = self.sm_id;
                let key = (raft_sid, sm_id, fn_id, pattern_id);
                let svr_subs = self.subscriptions.read();
                debug!("Subs key: {:?}", svr_subs.subscriptions.keys());
                debug!("Looking for: {:?}", &key);
                if let Some(sub_ids) = svr_subs.subscriptions.get(&key) {
                    let data = bincode::serialize(&data);
                    let sub_result: Vec<_> = sub_ids.iter().map(|sub_id| {
                        if let Some(subscriber_id) = svr_subs.sub_suber.get(&sub_id) {
                            if let Some(subscriber) = svr_subs.subscribers.get(&subscriber_id) {
                                let data = data.clone();
                                let client = subscriber.client.clone();
                                Ok(client.notify(&key, &data))
                            } else {
                                Err(NotifyFailure::CannotFindSubscriber)
                            }
                        } else {
                            Err(NotifyFailure::CannotFindSubscribers)
                        }
                    }).collect();
                    let errors = sub_result.iter()
                        .filter(|r| r.is_err())
                        .map(|r| {if let &Err(e) = r { Some(e) } else { None }})
                        .map(|o| o.clone().unwrap())
                        .collect::<Vec<NotifyFailure>>();
                    let response = sub_result.into_iter()
                        .filter(|r| r.is_ok())
                        .map(|r| r.unwrap())
                        .map(|req| req.wait())
                        .collect::<Vec<_>>();
                    return Ok((sub_ids.len(), errors, response));
                } else {
                    return Err(NotifyFailure::CannotFindSubscription)
                }
            },
            _ => {
                return Err(NotifyFailure::OpTypeNotSubscribe)
            }
        }
    }
}

pub fn notify<R, F>(callback: &Option<SMCallback>, func: &RaftMsg<R>, data: F)
    where F: Fn() -> R,
          R: serde::Serialize + Send + Sync {
    if let Some(ref callback) = *callback {
        callback.notify(func, data());
    }
}<|endoftext|>


<commit_before>extern crate difference_of_squares as squares;

#[test]
fn test_square_of_sum_5() {
    assert_eq!(225, squares::square_of_sum(5));
}

#[test]
#[ignore]
fn test_sum_of_squares_5() {
    assert_eq!(55, squares::sum_of_squares(5));
}

#[test]
#[ignore]
fn test_difference_5() {
    assert_eq!(170, squares::difference(5));
}

#[test]
#[ignore]
fn test_square_of_sum_100() {
    assert_eq!(25502500, squares::square_of_sum(100));
}

#[test]
#[ignore]
fn test_sum_of_squares_100() {
    assert_eq!(338350, squares::sum_of_squares(100));
}

#[test]
#[ignore]
fn test_difference_100() {
    assert_eq!(25164150, squares::difference(100));
}
<commit_msg>difference-of-squares: Test one function at a time<commit_after>extern crate difference_of_squares as squares;

#[test]
fn test_square_of_sum_5() {
    assert_eq!(225, squares::square_of_sum(5));
}

#[test]
#[ignore]
fn test_square_of_sum_100() {
    assert_eq!(25502500, squares::square_of_sum(100));
}

#[test]
#[ignore]
fn test_sum_of_squares_5() {
    assert_eq!(55, squares::sum_of_squares(5));
}

#[test]
#[ignore]
fn test_sum_of_squares_100() {
    assert_eq!(338350, squares::sum_of_squares(100));
}

#[test]
#[ignore]
fn test_difference_5() {
    assert_eq!(170, squares::difference(5));
}

#[test]
#[ignore]
fn test_difference_100() {
    assert_eq!(25164150, squares::difference(100));
}
<|endoftext|>


<commit_before>// Verifies that no_sanitze attribute can be used to
// selectively disable sanitizer instrumentation.
//
// needs-sanitizer-address
// compile-flags: -Zsanitizer=address

#![crate_type="lib"]
#![feature(no_sanitize)]

// CHECK-LABEL: ; sanitizer_no_sanitize::unsanitized
// CHECK-NEXT:  ; Function Attrs:
// CHECK-NOT:   sanitize_address
// CHECK:       start:
// CHECK-NOT:   call void @__asan_report_load
// CHECK:       }
#[no_sanitize(address)]
pub fn unsanitized(b: &mut u8) -> u8 {
    *b
}

// CHECK-LABEL: ; sanitizer_no_sanitize::sanitized
// CHECK-NEXT:  ; Function Attrs:
// CHECK:       sanitize_address
// CHECK:       start:
// CHECK:       call void @__asan_report_load
// CHECK:       }
pub fn sanitized(b: &mut u8) -> u8 {
    *b
}
<commit_msg>Fix typo in code comment<commit_after>// Verifies that no_sanitize attribute can be used to
// selectively disable sanitizer instrumentation.
//
// needs-sanitizer-address
// compile-flags: -Zsanitizer=address

#![crate_type="lib"]
#![feature(no_sanitize)]

// CHECK-LABEL: ; sanitizer_no_sanitize::unsanitized
// CHECK-NEXT:  ; Function Attrs:
// CHECK-NOT:   sanitize_address
// CHECK:       start:
// CHECK-NOT:   call void @__asan_report_load
// CHECK:       }
#[no_sanitize(address)]
pub fn unsanitized(b: &mut u8) -> u8 {
    *b
}

// CHECK-LABEL: ; sanitizer_no_sanitize::sanitized
// CHECK-NEXT:  ; Function Attrs:
// CHECK:       sanitize_address
// CHECK:       start:
// CHECK:       call void @__asan_report_load
// CHECK:       }
pub fn sanitized(b: &mut u8) -> u8 {
    *b
}
<|endoftext|>


<commit_before>use cssparser::Parser;
use markup5ever::{expanded_name, local_name, namespace_url, ns};
use nalgebra::{Matrix3, Matrix4x5, Matrix5, Vector5};

use crate::drawing_ctx::DrawingCtx;
use crate::error::*;
use crate::node::{NodeResult, NodeTrait, RsvgNode};
use crate::number_list::{NumberList, NumberListLength};
use crate::parsers::{Parse, ParseValue};
use crate::property_bag::PropertyBag;
use crate::surface_utils::{
    iterators::Pixels, shared_surface::SharedImageSurface, ImageSurfaceDataExt, Pixel,
};
use crate::util::clamp;

use super::context::{FilterContext, FilterOutput, FilterResult};
use super::{FilterEffect, FilterError, PrimitiveWithInput};

/// Color matrix operation types.
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
enum OperationType {
    Matrix,
    Saturate,
    HueRotate,
    LuminanceToAlpha,
}

impl Default for OperationType {
    fn default() -> Self {
        OperationType::Matrix
    }
}

/// The `feColorMatrix` filter primitive.
pub struct FeColorMatrix {
    base: PrimitiveWithInput,
    matrix: Matrix5<f64>,
}

impl Default for FeColorMatrix {
    /// Constructs a new `ColorMatrix` with empty properties.
    #[inline]
    fn default() -> FeColorMatrix {
        FeColorMatrix {
            base: PrimitiveWithInput::new::<Self>(),
            matrix: Matrix5::identity(),
        }
    }
}

impl NodeTrait for FeColorMatrix {
    impl_node_as_filter_effect!();

    fn set_atts(&mut self, parent: Option<&RsvgNode>, pbag: &PropertyBag<'_>) -> NodeResult {
        self.base.set_atts(parent, pbag)?;

        // First, determine the operation type.
        let mut operation_type = Default::default();
        for (attr, value) in pbag
            .iter()
            .filter(|(attr, _)| attr.expanded() == expanded_name!("", "type"))
        {
            operation_type = attr.parse(value)?;
        }

        // Now read the matrix correspondingly.
        // LuminanceToAlpha doesn't accept any matrix.
        if operation_type == OperationType::LuminanceToAlpha {
            self.matrix = {
                #[cfg_attr(rustfmt, rustfmt_skip)]
                Matrix5::new(
                    0.0,    0.0,    0.0,    0.0, 0.0,
                    0.0,    0.0,    0.0,    0.0, 0.0,
                    0.0,    0.0,    0.0,    0.0, 0.0,
                    0.2125, 0.7154, 0.0721, 0.0, 0.0,
                    0.0,    0.0,    0.0,    0.0, 1.0,
                )
            };
        } else {
            for (attr, value) in pbag
                .iter()
                .filter(|(attr, _)| attr.expanded() == expanded_name!("", "values"))
            {
                let new_matrix = match operation_type {
                    OperationType::LuminanceToAlpha => unreachable!(),
                    OperationType::Matrix => {
                        let NumberList(v) =
                            NumberList::parse_str(value, NumberListLength::Exact(20))
                                .attribute(attr)?;
                        let matrix = Matrix4x5::from_row_slice(&v);
                        let mut matrix = matrix.fixed_resize(0.0);
                        matrix[(4, 4)] = 1.0;
                        matrix
                    }
                    OperationType::Saturate => {
                        let s: f64 = attr.parse_and_validate(value, |s| {
                            if s < 0.0 || s > 1.0 {
                                Err(ValueErrorKind::value_error("expected value from 0 to 1"))
                            } else {
                                Ok(s)
                            }
                        })?;

                        #[cfg_attr(rustfmt, rustfmt_skip)]
                        Matrix5::new(
                            0.213 + 0.787 * s, 0.715 - 0.715 * s, 0.072 - 0.072 * s, 0.0, 0.0,
                            0.213 - 0.213 * s, 0.715 + 0.285 * s, 0.072 - 0.072 * s, 0.0, 0.0,
                            0.213 - 0.213 * s, 0.715 - 0.715 * s, 0.072 + 0.928 * s, 0.0, 0.0,
                            0.0,               0.0,               0.0,               1.0, 0.0,
                            0.0,               0.0,               0.0,               0.0, 1.0,
                        )
                    }
                    OperationType::HueRotate => {
                        let degrees: f64 = attr.parse(value)?;
                        let (sin, cos) = degrees.to_radians().sin_cos();

                        #[cfg_attr(rustfmt, rustfmt_skip)]
                        let a = Matrix3::new(
                            0.213, 0.715, 0.072,
                            0.213, 0.715, 0.072,
                            0.213, 0.715, 0.072,
                        );

                        #[cfg_attr(rustfmt, rustfmt_skip)]
                        let b = Matrix3::new(
                             0.787, -0.715, -0.072,
                            -0.213,  0.285, -0.072,
                            -0.213, -0.715,  0.928,
                        );

                        #[cfg_attr(rustfmt, rustfmt_skip)]
                        let c = Matrix3::new(
                            -0.213, -0.715,  0.928,
                             0.143,  0.140, -0.283,
                            -0.787,  0.715,  0.072,
                        );

                        let top_left = a + b * cos + c * sin;

                        let mut matrix = top_left.fixed_resize(0.0);
                        matrix[(3, 3)] = 1.0;
                        matrix[(4, 4)] = 1.0;
                        matrix
                    }
                };

                self.matrix = new_matrix;
            }
        }

        Ok(())
    }
}

impl FilterEffect for FeColorMatrix {
    fn render(
        &self,
        _node: &RsvgNode,
        ctx: &FilterContext,
        draw_ctx: &mut DrawingCtx,
    ) -> Result<FilterResult, FilterError> {
        let input = self.base.get_input(ctx, draw_ctx)?;
        let bounds = self
            .base
            .get_bounds(ctx)
            .add_input(&input)
            .into_irect(draw_ctx);

        let mut output_surface = cairo::ImageSurface::create(
            cairo::Format::ARgb32,
            ctx.source_graphic().width(),
            ctx.source_graphic().height(),
        )?;

        let output_stride = output_surface.get_stride() as usize;
        {
            let mut output_data = output_surface.get_data().unwrap();

            for (x, y, pixel) in Pixels::within(input.surface(), bounds) {
                let alpha = f64::from(pixel.a) / 255f64;

                let pixel_vec = if alpha == 0.0 {
                    Vector5::new(0.0, 0.0, 0.0, 0.0, 1.0)
                } else {
                    Vector5::new(
                        f64::from(pixel.r) / 255f64 / alpha,
                        f64::from(pixel.g) / 255f64 / alpha,
                        f64::from(pixel.b) / 255f64 / alpha,
                        alpha,
                        1.0,
                    )
                };
                let mut new_pixel_vec = Vector5::zeros();
                self.matrix.mul_to(&pixel_vec, &mut new_pixel_vec);

                let new_alpha = clamp(new_pixel_vec[3], 0.0, 1.0);

                let premultiply = |x: f64| ((clamp(x, 0.0, 1.0) * new_alpha * 255f64) + 0.5) as u8;

                let output_pixel = Pixel {
                    r: premultiply(new_pixel_vec[0]),
                    g: premultiply(new_pixel_vec[1]),
                    b: premultiply(new_pixel_vec[2]),
                    a: ((new_alpha * 255f64) + 0.5) as u8,
                };

                output_data.set_pixel(output_stride, output_pixel, x, y);
            }
        }

        Ok(FilterResult {
            name: self.base.result.clone(),
            output: FilterOutput {
                surface: SharedImageSurface::wrap(output_surface, input.surface().surface_type())?,
                bounds,
            },
        })
    }

    #[inline]
    fn is_affected_by_color_interpolation_filters(&self) -> bool {
        true
    }
}

impl Parse for OperationType {
    fn parse<'i>(parser: &mut Parser<'i, '_>) -> Result<Self, ParseError<'i>> {
        Ok(parse_identifiers!(
            parser,
            "matrix" => OperationType::Matrix,
            "saturate" => OperationType::Saturate,
            "hueRotate" => OperationType::HueRotate,
            "luminanceToAlpha" => OperationType::LuminanceToAlpha,
        )?)
    }
}
<commit_msg>filters: port color matrix to ExclusiveImageSurface<commit_after>use cssparser::Parser;
use markup5ever::{expanded_name, local_name, namespace_url, ns};
use nalgebra::{Matrix3, Matrix4x5, Matrix5, Vector5};

use crate::drawing_ctx::DrawingCtx;
use crate::error::*;
use crate::node::{NodeResult, NodeTrait, RsvgNode};
use crate::number_list::{NumberList, NumberListLength};
use crate::parsers::{Parse, ParseValue};
use crate::property_bag::PropertyBag;
use crate::surface_utils::{iterators::Pixels, shared_surface::ExclusiveImageSurface, Pixel};
use crate::util::clamp;

use super::context::{FilterContext, FilterOutput, FilterResult};
use super::{FilterEffect, FilterError, PrimitiveWithInput};

/// Color matrix operation types.
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
enum OperationType {
    Matrix,
    Saturate,
    HueRotate,
    LuminanceToAlpha,
}

impl Default for OperationType {
    fn default() -> Self {
        OperationType::Matrix
    }
}

/// The `feColorMatrix` filter primitive.
pub struct FeColorMatrix {
    base: PrimitiveWithInput,
    matrix: Matrix5<f64>,
}

impl Default for FeColorMatrix {
    /// Constructs a new `ColorMatrix` with empty properties.
    #[inline]
    fn default() -> FeColorMatrix {
        FeColorMatrix {
            base: PrimitiveWithInput::new::<Self>(),
            matrix: Matrix5::identity(),
        }
    }
}

impl NodeTrait for FeColorMatrix {
    impl_node_as_filter_effect!();

    fn set_atts(&mut self, parent: Option<&RsvgNode>, pbag: &PropertyBag<'_>) -> NodeResult {
        self.base.set_atts(parent, pbag)?;

        // First, determine the operation type.
        let mut operation_type = Default::default();
        for (attr, value) in pbag
            .iter()
            .filter(|(attr, _)| attr.expanded() == expanded_name!("", "type"))
        {
            operation_type = attr.parse(value)?;
        }

        // Now read the matrix correspondingly.
        // LuminanceToAlpha doesn't accept any matrix.
        if operation_type == OperationType::LuminanceToAlpha {
            self.matrix = {
                #[cfg_attr(rustfmt, rustfmt_skip)]
                Matrix5::new(
                    0.0,    0.0,    0.0,    0.0, 0.0,
                    0.0,    0.0,    0.0,    0.0, 0.0,
                    0.0,    0.0,    0.0,    0.0, 0.0,
                    0.2125, 0.7154, 0.0721, 0.0, 0.0,
                    0.0,    0.0,    0.0,    0.0, 1.0,
                )
            };
        } else {
            for (attr, value) in pbag
                .iter()
                .filter(|(attr, _)| attr.expanded() == expanded_name!("", "values"))
            {
                let new_matrix = match operation_type {
                    OperationType::LuminanceToAlpha => unreachable!(),
                    OperationType::Matrix => {
                        let NumberList(v) =
                            NumberList::parse_str(value, NumberListLength::Exact(20))
                                .attribute(attr)?;
                        let matrix = Matrix4x5::from_row_slice(&v);
                        let mut matrix = matrix.fixed_resize(0.0);
                        matrix[(4, 4)] = 1.0;
                        matrix
                    }
                    OperationType::Saturate => {
                        let s: f64 = attr.parse_and_validate(value, |s| {
                            if s < 0.0 || s > 1.0 {
                                Err(ValueErrorKind::value_error("expected value from 0 to 1"))
                            } else {
                                Ok(s)
                            }
                        })?;

                        #[cfg_attr(rustfmt, rustfmt_skip)]
                        Matrix5::new(
                            0.213 + 0.787 * s, 0.715 - 0.715 * s, 0.072 - 0.072 * s, 0.0, 0.0,
                            0.213 - 0.213 * s, 0.715 + 0.285 * s, 0.072 - 0.072 * s, 0.0, 0.0,
                            0.213 - 0.213 * s, 0.715 - 0.715 * s, 0.072 + 0.928 * s, 0.0, 0.0,
                            0.0,               0.0,               0.0,               1.0, 0.0,
                            0.0,               0.0,               0.0,               0.0, 1.0,
                        )
                    }
                    OperationType::HueRotate => {
                        let degrees: f64 = attr.parse(value)?;
                        let (sin, cos) = degrees.to_radians().sin_cos();

                        #[cfg_attr(rustfmt, rustfmt_skip)]
                        let a = Matrix3::new(
                            0.213, 0.715, 0.072,
                            0.213, 0.715, 0.072,
                            0.213, 0.715, 0.072,
                        );

                        #[cfg_attr(rustfmt, rustfmt_skip)]
                        let b = Matrix3::new(
                             0.787, -0.715, -0.072,
                            -0.213,  0.285, -0.072,
                            -0.213, -0.715,  0.928,
                        );

                        #[cfg_attr(rustfmt, rustfmt_skip)]
                        let c = Matrix3::new(
                            -0.213, -0.715,  0.928,
                             0.143,  0.140, -0.283,
                            -0.787,  0.715,  0.072,
                        );

                        let top_left = a + b * cos + c * sin;

                        let mut matrix = top_left.fixed_resize(0.0);
                        matrix[(3, 3)] = 1.0;
                        matrix[(4, 4)] = 1.0;
                        matrix
                    }
                };

                self.matrix = new_matrix;
            }
        }

        Ok(())
    }
}

impl FilterEffect for FeColorMatrix {
    fn render(
        &self,
        _node: &RsvgNode,
        ctx: &FilterContext,
        draw_ctx: &mut DrawingCtx,
    ) -> Result<FilterResult, FilterError> {
        let input = self.base.get_input(ctx, draw_ctx)?;
        let bounds = self
            .base
            .get_bounds(ctx)
            .add_input(&input)
            .into_irect(draw_ctx);

        let mut surface = ExclusiveImageSurface::new(
            ctx.source_graphic().width(),
            ctx.source_graphic().height(),
            input.surface().surface_type(),
        )?;

        for (x, y, pixel) in Pixels::within(input.surface(), bounds) {
            let alpha = f64::from(pixel.a) / 255f64;

            let pixel_vec = if alpha == 0.0 {
                Vector5::new(0.0, 0.0, 0.0, 0.0, 1.0)
            } else {
                Vector5::new(
                    f64::from(pixel.r) / 255f64 / alpha,
                    f64::from(pixel.g) / 255f64 / alpha,
                    f64::from(pixel.b) / 255f64 / alpha,
                    alpha,
                    1.0,
                )
            };
            let mut new_pixel_vec = Vector5::zeros();
            self.matrix.mul_to(&pixel_vec, &mut new_pixel_vec);

            let new_alpha = clamp(new_pixel_vec[3], 0.0, 1.0);

            let premultiply = |x: f64| ((clamp(x, 0.0, 1.0) * new_alpha * 255f64) + 0.5) as u8;

            let output_pixel = Pixel {
                r: premultiply(new_pixel_vec[0]),
                g: premultiply(new_pixel_vec[1]),
                b: premultiply(new_pixel_vec[2]),
                a: ((new_alpha * 255f64) + 0.5) as u8,
            };

            surface.set_pixel(output_pixel, x, y);
        }

        Ok(FilterResult {
            name: self.base.result.clone(),
            output: FilterOutput {
                surface: surface.share()?,
                bounds,
            },
        })
    }

    #[inline]
    fn is_affected_by_color_interpolation_filters(&self) -> bool {
        true
    }
}

impl Parse for OperationType {
    fn parse<'i>(parser: &mut Parser<'i, '_>) -> Result<Self, ParseError<'i>> {
        Ok(parse_identifiers!(
            parser,
            "matrix" => OperationType::Matrix,
            "saturate" => OperationType::Saturate,
            "hueRotate" => OperationType::HueRotate,
            "luminanceToAlpha" => OperationType::LuminanceToAlpha,
        )?)
    }
}
<|endoftext|>


<commit_before>extern crate gimli;
extern crate getopts;
extern crate memmap;
extern crate object;

use object::Object;
use std::cell::Cell;
use std::env;
use std::io;
use std::io::Write;
use std::fs;
use std::process;

#[derive(Default)]
struct Flags {
    info: bool,
    line: bool,
    aranges: bool,
}

fn print_usage(opts: &getopts::Options) -> ! {
    let brief = format!("Usage: {} <options> <file>", env::args().next().unwrap());
    write!(&mut io::stderr(), "{}", opts.usage(&brief)).ok();
    process::exit(1);
}

fn main() {
    let mut opts = getopts::Options::new();
    opts.optflag("i", "", "print .debug_info and .debug_types sections");
    opts.optflag("l", "", "print .debug_line section");
    opts.optflag("r", "", "print .debug_aranges section");

    let matches = match opts.parse(env::args().skip(1)) {
        Ok(m) => m,
        Err(e) => {
            writeln!(&mut io::stderr(), "{:?}\n", e).ok();
            print_usage(&opts);
        }
    };
    if matches.free.is_empty() {
        print_usage(&opts);
    }

    let mut all = true;
    let mut flags = Flags::default();
    if matches.opt_present("i") {
        flags.info = true;
        all = false;
    }
    if matches.opt_present("l") {
        flags.line = true;
        all = false;
    }
    if matches.opt_present("r") {
        flags.aranges = true;
        all = false;
    }
    if all {
        flags.info = true;
        flags.line = true;
        flags.aranges = true;
    }

    for file_path in matches.free {
        println!("{}", file_path);
        println!("");

        let file = fs::File::open(&file_path).expect("Should open file");
        let file = memmap::Mmap::open(&file, memmap::Protection::Read)
            .expect("Should create a mmap for file");
        let file = object::File::parse(unsafe { file.as_slice() });

        if file.is_little_endian() {
            dump_file::<gimli::LittleEndian>(file, &flags);
        } else {
            dump_file::<gimli::BigEndian>(file, &flags);
        }
    }
}

fn dump_file<Endian>(file: object::File, flags: &Flags)
    where Endian: gimli::Endianity
{
    let debug_abbrev = file.get_section(".debug_abbrev").unwrap_or(&[]);
    let debug_abbrev = gimli::DebugAbbrev::<Endian>::new(debug_abbrev);
    let debug_str = file.get_section(".debug_str").unwrap_or(&[]);
    let debug_str = gimli::DebugStr::<Endian>::new(debug_str);

    if flags.info {
        dump_info(&file, debug_abbrev, debug_str);
        dump_types(&file, debug_abbrev, debug_str);
    }
    if flags.line {
        dump_line(&file, debug_abbrev);
    }
    if flags.aranges {
        dump_aranges::<Endian>(&file);
    }
}

fn dump_info<Endian>(file: &object::File,
                     debug_abbrev: gimli::DebugAbbrev<Endian>,
                     debug_str: gimli::DebugStr<Endian>)
    where Endian: gimli::Endianity
{
    if let Some(debug_info) = file.get_section(".debug_info") {
        println!(".debug_info");
        println!("");

        let debug_info = gimli::DebugInfo::<Endian>::new(&debug_info);

        let mut iter = debug_info.units();
        while let Some(unit) = iter.next().expect("Should parse compilation unit") {
            let abbrevs = unit.abbreviations(debug_abbrev)
                .expect("Error parsing abbreviations");

            dump_entries(unit.entries(&abbrevs), debug_str);
        }
    }
}

fn dump_types<Endian>(file: &object::File,
                      debug_abbrev: gimli::DebugAbbrev<Endian>,
                      debug_str: gimli::DebugStr<Endian>)
    where Endian: gimli::Endianity
{
    if let Some(debug_types) = file.get_section(".debug_types") {
        println!(".debug_types");
        println!("");

        let debug_types = gimli::DebugTypes::<Endian>::new(&debug_types);

        let mut iter = debug_types.units();
        while let Some(unit) = iter.next().expect("Should parse the unit OK") {
            let abbrevs = unit.abbreviations(debug_abbrev)
                .expect("Error parsing abbreviations");

            dump_entries(unit.entries(&abbrevs), debug_str);
        }
    }
}

fn dump_entries<Endian>(mut entries: gimli::EntriesCursor<Endian>,
                        debug_str: gimli::DebugStr<Endian>)
    where Endian: gimli::Endianity
{
    let depth = Cell::new(0);
    while let Some((delta_depth, entry)) = entries.next_dfs().expect("Should parse next dfs") {
        depth.set(depth.get() + delta_depth);
        let indent = || {
            for _ in 0..(depth.get() as usize) {
                print!("        ");
            }
        };

        indent();
        println!("<{}> <{}>", entry.offset(), entry.tag());

        let mut attrs = entry.attrs();
        while let Some(attr) = attrs.next().expect("Should parse attribute OK") {
            indent();
            let mut value = attr.value();
            if let gimli::AttributeValue::DebugStrRef(o) = value {
                let s = debug_str.get_str(o).expect("Should have valid str offset");
                value = gimli::AttributeValue::String(s)
            }
            println!("    {} = {:?}", attr.name(), value);
        }
    }
}

fn dump_line<Endian>(file: &object::File, debug_abbrev: gimli::DebugAbbrev<Endian>)
    where Endian: gimli::Endianity
{
    let debug_line = file.get_section(".debug_line");
    let debug_info = file.get_section(".debug_info");

    if let (Some(debug_line), Some(debug_info)) = (debug_line, debug_info) {
        println!(".debug_line");
        println!("");

        let debug_line = gimli::DebugLine::<Endian>::new(&debug_line);
        let debug_info = gimli::DebugInfo::<Endian>::new(&debug_info);

        let mut iter = debug_info.units();
        while let Some(unit) = iter.next().expect("Should parse unit header OK") {
            let abbrevs = unit.abbreviations(debug_abbrev)
                .expect("Error parsing abbreviations");

            let mut cursor = unit.entries(&abbrevs);
            cursor.next_dfs().expect("Should parse next dfs");

            let root = cursor.current().expect("Should have a root DIE");
            let offset = match root.attr_value(gimli::DW_AT_stmt_list) {
                Some(gimli::AttributeValue::DebugLineRef(offset)) => offset,
                _ => continue,
            };

            let header =
                gimli::LineNumberProgramHeader::new(debug_line, offset, unit.address_size());
            if let Ok(header) = header {
                println!("");
                println!("Offset:                             0x{:x}", offset.0);
                println!("Length:                             {}",
                         header.unit_length());
                println!("DWARF version:                      {}", header.version());
                println!("Prologue length:                    {}",
                         header.header_length());
                println!("Minimum instruction length:         {}",
                         header.minimum_instruction_length());
                println!("Maximum operations per instruction: {}",
                         header.maximum_operations_per_instruction());
                println!("Default is_stmt:                    {}",
                         header.default_is_stmt());
                println!("Line base:                          {}", header.line_base());
                println!("Line range:                         {}",
                         header.line_range());
                println!("Opcode base:                        {}",
                         header.opcode_base());

                println!("");
                println!("Opcodes:");
                for (i, length) in header.standard_opcode_lengths().iter().enumerate() {
                    println!("  Opcode {} as {} args", i + 1, length);
                }

                println!("");
                println!("The Directory Table:");
                for (i, dir) in header.include_directories().iter().enumerate() {
                    println!("  {} {}", i + 1, dir.to_string_lossy());
                }

                println!("");
                println!("The File Name Table");
                println!("  Entry\tDir\tTime\tSize\tName");
                for (i, file) in header.file_names().iter().enumerate() {
                    println!("  {}\t{}\t{}\t{}\t{}",
                             i + 1,
                             file.directory_index(),
                             file.last_modification(),
                             file.length(),
                             file.path_name().to_string_lossy());
                }

                println!("");
                println!("Line Number Statements:");
                let mut opcodes = header.opcodes();
                while let Some(opcode) = opcodes.next_opcode(&header)
                    .expect("Should parse opcode OK") {
                    println!("  {}", opcode);
                }

                println!("");
                println!("Line Number Rows:");
                println!("<pc>        [lno,col]");
                let mut state_machine = gimli::StateMachine::new(header);
                let mut file_index = 0;
                while let Some(row) = state_machine.next_row()
                    .expect("Should parse row OK") {
                    let line = row.line().unwrap_or(0);
                    let column = match row.column() {
                        gimli::ColumnType::Column(column) => column,
                        gimli::ColumnType::LeftEdge => 0,
                    };
                    print!("0x{:08x}  [{:4},{:2}]", row.address(), line, column);
                    if row.is_stmt() {
                        print!(" NS");
                    }
                    if row.basic_block() {
                        print!(" BB");
                    }
                    if row.end_sequence() {
                        print!(" ET");
                    }
                    if row.prologue_end() {
                        print!(" PE");
                    }
                    if row.epilogue_begin() {
                        print!(" EB");
                    }
                    if row.isa() != 0 {
                        print!(" IS={}", row.isa());
                    }
                    if row.discriminator() != 0 {
                        print!(" DI={}", row.discriminator());
                    }
                    if file_index != row.file_index() {
                        file_index = row.file_index();
                        if let Ok(file) = row.file() {
                            if let Some(directory) = file.directory(row.header()) {
                                print!(" uri: \"{}/{}\"",
                                       directory.to_string_lossy(),
                                       file.path_name().to_string_lossy());
                            } else {
                                print!(" uri: \"{}\"", file.path_name().to_string_lossy());
                            }
                        }
                    }
                    println!("");
                }
            }
        }
    }
}

fn dump_aranges<Endian>(file: &object::File)
    where Endian: gimli::Endianity
{
    let debug_aranges = file.get_section(".debug_aranges");
    let debug_info = file.get_section(".debug_info");

    if let (Some(debug_aranges), Some(debug_info)) = (debug_aranges, debug_info) {
        println!(".debug_aranges");
        println!("");

        let debug_aranges = gimli::DebugAranges::<Endian>::new(debug_aranges);
        let debug_info = gimli::DebugInfo::<Endian>::new(debug_info);

        let mut cu_die_offset = gimli::DebugInfoOffset(0);
        let mut prev_cu_offset = None;
        let mut aranges = debug_aranges.items();
        while let Some(arange) = aranges.next().expect("Should parse arange OK") {
            let cu_offset = arange.debug_info_offset();
            if Some(cu_offset) != prev_cu_offset {
                let cu = debug_info.header_from_offset(cu_offset)
                    .expect("Should parse unit header OK");
                cu_die_offset = gimli::DebugInfoOffset(cu_offset.0 + cu.header_size() as u64);
                prev_cu_offset = Some(cu_offset);
            }
            if let Some(segment) = arange.segment() {
                print!("arange starts at seg,off 0x{:08x},0x{:08x}, ",
                       segment,
                       arange.address());
            } else {
                print!("arange starts at 0x{:08x}, ", arange.address());
            }
            println!("length of 0x{:08x}, cu_die_offset = 0x{:08x}",
                     arange.length(),
                     cu_die_offset.0);
        }
    }
}
<commit_msg>dwarfdump: only print filename for multiple files<commit_after>extern crate gimli;
extern crate getopts;
extern crate memmap;
extern crate object;

use object::Object;
use std::cell::Cell;
use std::env;
use std::io;
use std::io::Write;
use std::fs;
use std::process;

#[derive(Default)]
struct Flags {
    info: bool,
    line: bool,
    aranges: bool,
}

fn print_usage(opts: &getopts::Options) -> ! {
    let brief = format!("Usage: {} <options> <file>", env::args().next().unwrap());
    write!(&mut io::stderr(), "{}", opts.usage(&brief)).ok();
    process::exit(1);
}

fn main() {
    let mut opts = getopts::Options::new();
    opts.optflag("i", "", "print .debug_info and .debug_types sections");
    opts.optflag("l", "", "print .debug_line section");
    opts.optflag("r", "", "print .debug_aranges section");

    let matches = match opts.parse(env::args().skip(1)) {
        Ok(m) => m,
        Err(e) => {
            writeln!(&mut io::stderr(), "{:?}\n", e).ok();
            print_usage(&opts);
        }
    };
    if matches.free.is_empty() {
        print_usage(&opts);
    }

    let mut all = true;
    let mut flags = Flags::default();
    if matches.opt_present("i") {
        flags.info = true;
        all = false;
    }
    if matches.opt_present("l") {
        flags.line = true;
        all = false;
    }
    if matches.opt_present("r") {
        flags.aranges = true;
        all = false;
    }
    if all {
        flags.info = true;
        flags.line = true;
        flags.aranges = true;
    }

    for file_path in &matches.free {
        if matches.free.len() != 1 {
            println!("{}", file_path);
            println!("");
        }

        let file = fs::File::open(&file_path).expect("Should open file");
        let file = memmap::Mmap::open(&file, memmap::Protection::Read)
            .expect("Should create a mmap for file");
        let file = object::File::parse(unsafe { file.as_slice() });

        if file.is_little_endian() {
            dump_file::<gimli::LittleEndian>(file, &flags);
        } else {
            dump_file::<gimli::BigEndian>(file, &flags);
        }
    }
}

fn dump_file<Endian>(file: object::File, flags: &Flags)
    where Endian: gimli::Endianity
{
    let debug_abbrev = file.get_section(".debug_abbrev").unwrap_or(&[]);
    let debug_abbrev = gimli::DebugAbbrev::<Endian>::new(debug_abbrev);
    let debug_str = file.get_section(".debug_str").unwrap_or(&[]);
    let debug_str = gimli::DebugStr::<Endian>::new(debug_str);

    if flags.info {
        dump_info(&file, debug_abbrev, debug_str);
        dump_types(&file, debug_abbrev, debug_str);
    }
    if flags.line {
        dump_line(&file, debug_abbrev);
    }
    if flags.aranges {
        dump_aranges::<Endian>(&file);
    }
}

fn dump_info<Endian>(file: &object::File,
                     debug_abbrev: gimli::DebugAbbrev<Endian>,
                     debug_str: gimli::DebugStr<Endian>)
    where Endian: gimli::Endianity
{
    if let Some(debug_info) = file.get_section(".debug_info") {
        println!(".debug_info");
        println!("");

        let debug_info = gimli::DebugInfo::<Endian>::new(&debug_info);

        let mut iter = debug_info.units();
        while let Some(unit) = iter.next().expect("Should parse compilation unit") {
            let abbrevs = unit.abbreviations(debug_abbrev)
                .expect("Error parsing abbreviations");

            dump_entries(unit.entries(&abbrevs), debug_str);
        }
    }
}

fn dump_types<Endian>(file: &object::File,
                      debug_abbrev: gimli::DebugAbbrev<Endian>,
                      debug_str: gimli::DebugStr<Endian>)
    where Endian: gimli::Endianity
{
    if let Some(debug_types) = file.get_section(".debug_types") {
        println!(".debug_types");
        println!("");

        let debug_types = gimli::DebugTypes::<Endian>::new(&debug_types);

        let mut iter = debug_types.units();
        while let Some(unit) = iter.next().expect("Should parse the unit OK") {
            let abbrevs = unit.abbreviations(debug_abbrev)
                .expect("Error parsing abbreviations");

            dump_entries(unit.entries(&abbrevs), debug_str);
        }
    }
}

fn dump_entries<Endian>(mut entries: gimli::EntriesCursor<Endian>,
                        debug_str: gimli::DebugStr<Endian>)
    where Endian: gimli::Endianity
{
    let depth = Cell::new(0);
    while let Some((delta_depth, entry)) = entries.next_dfs().expect("Should parse next dfs") {
        depth.set(depth.get() + delta_depth);
        let indent = || {
            for _ in 0..(depth.get() as usize) {
                print!("        ");
            }
        };

        indent();
        println!("<{}> <{}>", entry.offset(), entry.tag());

        let mut attrs = entry.attrs();
        while let Some(attr) = attrs.next().expect("Should parse attribute OK") {
            indent();
            let mut value = attr.value();
            if let gimli::AttributeValue::DebugStrRef(o) = value {
                let s = debug_str.get_str(o).expect("Should have valid str offset");
                value = gimli::AttributeValue::String(s)
            }
            println!("    {} = {:?}", attr.name(), value);
        }
    }
}

fn dump_line<Endian>(file: &object::File, debug_abbrev: gimli::DebugAbbrev<Endian>)
    where Endian: gimli::Endianity
{
    let debug_line = file.get_section(".debug_line");
    let debug_info = file.get_section(".debug_info");

    if let (Some(debug_line), Some(debug_info)) = (debug_line, debug_info) {
        println!(".debug_line");
        println!("");

        let debug_line = gimli::DebugLine::<Endian>::new(&debug_line);
        let debug_info = gimli::DebugInfo::<Endian>::new(&debug_info);

        let mut iter = debug_info.units();
        while let Some(unit) = iter.next().expect("Should parse unit header OK") {
            let abbrevs = unit.abbreviations(debug_abbrev)
                .expect("Error parsing abbreviations");

            let mut cursor = unit.entries(&abbrevs);
            cursor.next_dfs().expect("Should parse next dfs");

            let root = cursor.current().expect("Should have a root DIE");
            let offset = match root.attr_value(gimli::DW_AT_stmt_list) {
                Some(gimli::AttributeValue::DebugLineRef(offset)) => offset,
                _ => continue,
            };

            let header =
                gimli::LineNumberProgramHeader::new(debug_line, offset, unit.address_size());
            if let Ok(header) = header {
                println!("");
                println!("Offset:                             0x{:x}", offset.0);
                println!("Length:                             {}",
                         header.unit_length());
                println!("DWARF version:                      {}", header.version());
                println!("Prologue length:                    {}",
                         header.header_length());
                println!("Minimum instruction length:         {}",
                         header.minimum_instruction_length());
                println!("Maximum operations per instruction: {}",
                         header.maximum_operations_per_instruction());
                println!("Default is_stmt:                    {}",
                         header.default_is_stmt());
                println!("Line base:                          {}", header.line_base());
                println!("Line range:                         {}",
                         header.line_range());
                println!("Opcode base:                        {}",
                         header.opcode_base());

                println!("");
                println!("Opcodes:");
                for (i, length) in header.standard_opcode_lengths().iter().enumerate() {
                    println!("  Opcode {} as {} args", i + 1, length);
                }

                println!("");
                println!("The Directory Table:");
                for (i, dir) in header.include_directories().iter().enumerate() {
                    println!("  {} {}", i + 1, dir.to_string_lossy());
                }

                println!("");
                println!("The File Name Table");
                println!("  Entry\tDir\tTime\tSize\tName");
                for (i, file) in header.file_names().iter().enumerate() {
                    println!("  {}\t{}\t{}\t{}\t{}",
                             i + 1,
                             file.directory_index(),
                             file.last_modification(),
                             file.length(),
                             file.path_name().to_string_lossy());
                }

                println!("");
                println!("Line Number Statements:");
                let mut opcodes = header.opcodes();
                while let Some(opcode) = opcodes.next_opcode(&header)
                    .expect("Should parse opcode OK") {
                    println!("  {}", opcode);
                }

                println!("");
                println!("Line Number Rows:");
                println!("<pc>        [lno,col]");
                let mut state_machine = gimli::StateMachine::new(header);
                let mut file_index = 0;
                while let Some(row) = state_machine.next_row()
                    .expect("Should parse row OK") {
                    let line = row.line().unwrap_or(0);
                    let column = match row.column() {
                        gimli::ColumnType::Column(column) => column,
                        gimli::ColumnType::LeftEdge => 0,
                    };
                    print!("0x{:08x}  [{:4},{:2}]", row.address(), line, column);
                    if row.is_stmt() {
                        print!(" NS");
                    }
                    if row.basic_block() {
                        print!(" BB");
                    }
                    if row.end_sequence() {
                        print!(" ET");
                    }
                    if row.prologue_end() {
                        print!(" PE");
                    }
                    if row.epilogue_begin() {
                        print!(" EB");
                    }
                    if row.isa() != 0 {
                        print!(" IS={}", row.isa());
                    }
                    if row.discriminator() != 0 {
                        print!(" DI={}", row.discriminator());
                    }
                    if file_index != row.file_index() {
                        file_index = row.file_index();
                        if let Ok(file) = row.file() {
                            if let Some(directory) = file.directory(row.header()) {
                                print!(" uri: \"{}/{}\"",
                                       directory.to_string_lossy(),
                                       file.path_name().to_string_lossy());
                            } else {
                                print!(" uri: \"{}\"", file.path_name().to_string_lossy());
                            }
                        }
                    }
                    println!("");
                }
            }
        }
    }
}

fn dump_aranges<Endian>(file: &object::File)
    where Endian: gimli::Endianity
{
    let debug_aranges = file.get_section(".debug_aranges");
    let debug_info = file.get_section(".debug_info");

    if let (Some(debug_aranges), Some(debug_info)) = (debug_aranges, debug_info) {
        println!(".debug_aranges");
        println!("");

        let debug_aranges = gimli::DebugAranges::<Endian>::new(debug_aranges);
        let debug_info = gimli::DebugInfo::<Endian>::new(debug_info);

        let mut cu_die_offset = gimli::DebugInfoOffset(0);
        let mut prev_cu_offset = None;
        let mut aranges = debug_aranges.items();
        while let Some(arange) = aranges.next().expect("Should parse arange OK") {
            let cu_offset = arange.debug_info_offset();
            if Some(cu_offset) != prev_cu_offset {
                let cu = debug_info.header_from_offset(cu_offset)
                    .expect("Should parse unit header OK");
                cu_die_offset = gimli::DebugInfoOffset(cu_offset.0 + cu.header_size() as u64);
                prev_cu_offset = Some(cu_offset);
            }
            if let Some(segment) = arange.segment() {
                print!("arange starts at seg,off 0x{:08x},0x{:08x}, ",
                       segment,
                       arange.address());
            } else {
                print!("arange starts at 0x{:08x}, ", arange.address());
            }
            println!("length of 0x{:08x}, cu_die_offset = 0x{:08x}",
                     arange.length(),
                     cu_die_offset.0);
        }
    }
}
<|endoftext|>


<commit_before>use livesplit_core::{Run, TimeSpan, Timer, TimerPhase, TimingMethod};
use super::{acc, acc_mut, alloc, output_str, output_time_span, own, own_drop};
use run::{NullableOwnedRun, OwnedRun};
use libc::c_char;
use shared_timer::OwnedSharedTimer;
use std::ptr;

pub type OwnedTimer = *mut Timer;
pub type NullableOwnedTimer = OwnedTimer;

#[no_mangle]
pub unsafe extern "C" fn Timer_new(run: OwnedRun) -> NullableOwnedTimer {
    Timer::new(own(run)).ok().map_or_else(ptr::null_mut, alloc)
}

#[no_mangle]
pub unsafe extern "C" fn Timer_into_shared(this: OwnedTimer) -> OwnedSharedTimer {
    alloc(own(this).into_shared())
}

#[no_mangle]
pub unsafe extern "C" fn Timer_drop(this: OwnedTimer) {
    own_drop(this);
}

#[no_mangle]
pub unsafe extern "C" fn Timer_replace_run(
    this: *mut Timer,
    run: *mut Run,
    update_splits: bool,
) -> bool {
    // This working correctly relies on panic = "abort",
    // as a panic would leave the run in an uninitialized state.
    let result = acc_mut(this).replace_run(ptr::read(run), update_splits);
    let was_successful = result.is_ok();
    let result = match result {
        Ok(r) | Err(r) => r,
    };
    ptr::write(run, result);
    was_successful
}

#[no_mangle]
pub unsafe extern "C" fn Timer_set_run(this: *mut Timer, run: OwnedRun) -> NullableOwnedRun {
    acc_mut(this)
        .set_run(own(run))
        .err()
        .map_or_else(ptr::null_mut, alloc)
}

#[no_mangle]
pub unsafe extern "C" fn Timer_start(this: *mut Timer) {
    acc_mut(this).start();
}

#[no_mangle]
pub unsafe extern "C" fn Timer_split(this: *mut Timer) {
    acc_mut(this).split();
}

#[no_mangle]
pub unsafe extern "C" fn Timer_split_or_start(this: *mut Timer) {
    acc_mut(this).split_or_start();
}

#[no_mangle]
pub unsafe extern "C" fn Timer_skip_split(this: *mut Timer) {
    acc_mut(this).skip_split();
}

#[no_mangle]
pub unsafe extern "C" fn Timer_undo_split(this: *mut Timer) {
    acc_mut(this).undo_split();
}

#[no_mangle]
pub unsafe extern "C" fn Timer_reset(this: *mut Timer, update_splits: bool) {
    acc_mut(this).reset(update_splits);
}

#[no_mangle]
pub unsafe extern "C" fn Timer_pause(this: *mut Timer) {
    acc_mut(this).pause();
}

#[no_mangle]
pub unsafe extern "C" fn Timer_resume(this: *mut Timer) {
    acc_mut(this).resume();
}

#[no_mangle]
pub unsafe extern "C" fn Timer_toggle_pause(this: *mut Timer) {
    acc_mut(this).toggle_pause();
}

#[no_mangle]
pub unsafe extern "C" fn Timer_toggle_pause_or_start(this: *mut Timer) {
    acc_mut(this).toggle_pause_or_start();
}

#[no_mangle]
pub unsafe extern "C" fn Timer_undo_all_pauses(this: *mut Timer) {
    acc_mut(this).undo_all_pauses();
}

#[no_mangle]
pub unsafe extern "C" fn Timer_current_timing_method(this: *const Timer) -> TimingMethod {
    acc(this).current_timing_method()
}

#[no_mangle]
pub unsafe extern "C" fn Timer_set_current_timing_method(this: *mut Timer, method: TimingMethod) {
    acc_mut(this).set_current_timing_method(method);
}

#[no_mangle]
pub unsafe extern "C" fn Timer_current_comparison(this: *const Timer) -> *const c_char {
    output_str(acc(this).current_comparison())
}

#[no_mangle]
pub unsafe extern "C" fn Timer_switch_to_next_comparison(this: *mut Timer) {
    acc_mut(this).switch_to_next_comparison();
}

#[no_mangle]
pub unsafe extern "C" fn Timer_switch_to_previous_comparison(this: *mut Timer) {
    acc_mut(this).switch_to_previous_comparison();
}

#[no_mangle]
pub unsafe extern "C" fn Timer_is_game_time_initialized(this: *const Timer) -> bool {
    acc(this).is_game_time_initialized()
}

#[no_mangle]
pub unsafe extern "C" fn Timer_initialize_game_time(this: *mut Timer) {
    acc_mut(this).initialize_game_time();
}

#[no_mangle]
pub unsafe extern "C" fn Timer_uninitialize_game_time(this: *mut Timer) {
    acc_mut(this).uninitialize_game_time();
}

#[no_mangle]
pub unsafe extern "C" fn Timer_is_game_time_paused(this: *const Timer) -> bool {
    acc(this).is_game_time_paused()
}

#[no_mangle]
pub unsafe extern "C" fn Timer_pause_game_time(this: *mut Timer) {
    acc_mut(this).pause_game_time();
}

#[no_mangle]
pub unsafe extern "C" fn Timer_unpause_game_time(this: *mut Timer) {
    acc_mut(this).unpause_game_time();
}

#[no_mangle]
pub unsafe extern "C" fn Timer_set_game_time(this: *mut Timer, time: *const TimeSpan) {
    acc_mut(this).set_game_time(*acc(time));
}

#[no_mangle]
pub unsafe extern "C" fn Timer_loading_times(this: *const Timer) -> *const TimeSpan {
    output_time_span(acc(this).loading_times())
}

#[no_mangle]
pub unsafe extern "C" fn Timer_set_loading_times(this: *mut Timer, time: *const TimeSpan) {
    acc_mut(this).set_loading_times(*acc(time));
}

#[no_mangle]
pub unsafe extern "C" fn Timer_current_phase(this: *const Timer) -> TimerPhase {
    acc(this).current_phase()
}

#[no_mangle]
pub unsafe extern "C" fn Timer_get_run(this: *const Timer) -> *const Run {
    acc(this).run()
}

#[no_mangle]
pub unsafe extern "C" fn Timer_print_debug(this: *const Timer) {
    println!("{:#?}", acc(this));
}
<commit_msg>Add binding for Timer.current_time<commit_after>use livesplit_core::{Run, TimeSpan, Timer, Time, TimerPhase, TimingMethod};
use super::{acc, acc_mut, alloc, output_str, output_time_span, output_time, own, own_drop};
use run::{NullableOwnedRun, OwnedRun};
use libc::c_char;
use shared_timer::OwnedSharedTimer;
use std::ptr;

pub type OwnedTimer = *mut Timer;
pub type NullableOwnedTimer = OwnedTimer;

#[no_mangle]
pub unsafe extern "C" fn Timer_new(run: OwnedRun) -> NullableOwnedTimer {
    Timer::new(own(run)).ok().map_or_else(ptr::null_mut, alloc)
}

#[no_mangle]
pub unsafe extern "C" fn Timer_into_shared(this: OwnedTimer) -> OwnedSharedTimer {
    alloc(own(this).into_shared())
}

#[no_mangle]
pub unsafe extern "C" fn Timer_drop(this: OwnedTimer) {
    own_drop(this);
}

#[no_mangle]
pub unsafe extern "C" fn Timer_replace_run(
    this: *mut Timer,
    run: *mut Run,
    update_splits: bool,
) -> bool {
    // This working correctly relies on panic = "abort",
    // as a panic would leave the run in an uninitialized state.
    let result = acc_mut(this).replace_run(ptr::read(run), update_splits);
    let was_successful = result.is_ok();
    let result = match result {
        Ok(r) | Err(r) => r,
    };
    ptr::write(run, result);
    was_successful
}

#[no_mangle]
pub unsafe extern "C" fn Timer_set_run(this: *mut Timer, run: OwnedRun) -> NullableOwnedRun {
    acc_mut(this)
        .set_run(own(run))
        .err()
        .map_or_else(ptr::null_mut, alloc)
}

#[no_mangle]
pub unsafe extern "C" fn Timer_start(this: *mut Timer) {
    acc_mut(this).start();
}

#[no_mangle]
pub unsafe extern "C" fn Timer_split(this: *mut Timer) {
    acc_mut(this).split();
}

#[no_mangle]
pub unsafe extern "C" fn Timer_split_or_start(this: *mut Timer) {
    acc_mut(this).split_or_start();
}

#[no_mangle]
pub unsafe extern "C" fn Timer_skip_split(this: *mut Timer) {
    acc_mut(this).skip_split();
}

#[no_mangle]
pub unsafe extern "C" fn Timer_undo_split(this: *mut Timer) {
    acc_mut(this).undo_split();
}

#[no_mangle]
pub unsafe extern "C" fn Timer_reset(this: *mut Timer, update_splits: bool) {
    acc_mut(this).reset(update_splits);
}

#[no_mangle]
pub unsafe extern "C" fn Timer_pause(this: *mut Timer) {
    acc_mut(this).pause();
}

#[no_mangle]
pub unsafe extern "C" fn Timer_resume(this: *mut Timer) {
    acc_mut(this).resume();
}

#[no_mangle]
pub unsafe extern "C" fn Timer_toggle_pause(this: *mut Timer) {
    acc_mut(this).toggle_pause();
}

#[no_mangle]
pub unsafe extern "C" fn Timer_toggle_pause_or_start(this: *mut Timer) {
    acc_mut(this).toggle_pause_or_start();
}

#[no_mangle]
pub unsafe extern "C" fn Timer_undo_all_pauses(this: *mut Timer) {
    acc_mut(this).undo_all_pauses();
}

#[no_mangle]
pub unsafe extern "C" fn Timer_current_timing_method(this: *const Timer) -> TimingMethod {
    acc(this).current_timing_method()
}

#[no_mangle]
pub unsafe extern "C" fn Timer_set_current_timing_method(this: *mut Timer, method: TimingMethod) {
    acc_mut(this).set_current_timing_method(method);
}

#[no_mangle]
pub unsafe extern "C" fn Timer_current_comparison(this: *const Timer) -> *const c_char {
    output_str(acc(this).current_comparison())
}

#[no_mangle]
pub unsafe extern "C" fn Timer_switch_to_next_comparison(this: *mut Timer) {
    acc_mut(this).switch_to_next_comparison();
}

#[no_mangle]
pub unsafe extern "C" fn Timer_switch_to_previous_comparison(this: *mut Timer) {
    acc_mut(this).switch_to_previous_comparison();
}

#[no_mangle]
pub unsafe extern "C" fn Timer_is_game_time_initialized(this: *const Timer) -> bool {
    acc(this).is_game_time_initialized()
}

#[no_mangle]
pub unsafe extern "C" fn Timer_initialize_game_time(this: *mut Timer) {
    acc_mut(this).initialize_game_time();
}

#[no_mangle]
pub unsafe extern "C" fn Timer_uninitialize_game_time(this: *mut Timer) {
    acc_mut(this).uninitialize_game_time();
}

#[no_mangle]
pub unsafe extern "C" fn Timer_is_game_time_paused(this: *const Timer) -> bool {
    acc(this).is_game_time_paused()
}

#[no_mangle]
pub unsafe extern "C" fn Timer_pause_game_time(this: *mut Timer) {
    acc_mut(this).pause_game_time();
}

#[no_mangle]
pub unsafe extern "C" fn Timer_unpause_game_time(this: *mut Timer) {
    acc_mut(this).unpause_game_time();
}

#[no_mangle]
pub unsafe extern "C" fn Timer_set_game_time(this: *mut Timer, time: *const TimeSpan) {
    acc_mut(this).set_game_time(*acc(time));
}

#[no_mangle]
pub unsafe extern "C" fn Timer_loading_times(this: *const Timer) -> *const TimeSpan {
    output_time_span(acc(this).loading_times())
}

#[no_mangle]
pub unsafe extern "C" fn Timer_set_loading_times(this: *mut Timer, time: *const TimeSpan) {
    acc_mut(this).set_loading_times(*acc(time));
}

#[no_mangle]
pub unsafe extern "C" fn Timer_current_phase(this: *const Timer) -> TimerPhase {
    acc(this).current_phase()
}

#[no_mangle]
pub unsafe extern "C" fn Timer_get_run(this: *const Timer) -> *const Run {
    acc(this).run()
}

#[no_mangle]
pub unsafe extern "C" fn Timer_print_debug(this: *const Timer) {
    println!("{:#?}", acc(this));
}

#[no_mangle]
pub unsafe extern "C" fn Timer_current_time(this: *const Timer) -> *const Time {
    output_time(acc(this).current_time())
}
<|endoftext|>