<commit_before>use connection::Connection;
use libproto::blockchain::{Block, Status};
use libproto::router::{MsgType, RoutingKey, SubModules};
use libproto::{Message, OperateType, SyncRequest, SyncResponse};
use rand::{thread_rng, Rng, ThreadRng};
use std::collections::{BTreeMap, HashSet, VecDeque};
use std::convert::{Into, TryFrom, TryInto};
use std::sync::{mpsc, Arc};
use std::time::{Duration, Instant};
use std::u8;
use Source;

const SYNC_STEP: u64 = 20;
const SYNC_TIME_OUT: u64 = 9;

/// Get messages and determine if need to synchronize or broadcast the current node status
pub struct Synchronizer {
    tx_pub: mpsc::Sender<(String, Vec<u8>)>,
    con: Arc<Connection>,
    current_status: Status,
    global_status: Status,
    sync_end_height: u64, //current_status <= sync_end_status
    is_synchronizing: bool,
    latest_status_lists: BTreeMap<u64, VecDeque<u32>>,
    block_lists: BTreeMap<u64, Block>,
    rand: ThreadRng,
    // Timer for each height processing
    remote_sync_time_out: Instant,
    /// local sync error
    local_sync_count: u8,
}

unsafe impl Sync for Synchronizer {}
unsafe impl Send for Synchronizer {}

impl Synchronizer {
    pub fn new(tx_pub: mpsc::Sender<(String, Vec<u8>)>, con: Arc<Connection>) -> Self {
        Synchronizer {
            tx_pub: tx_pub,
            con: con,
            current_status: Status::new(),
            global_status: Status::new(),
            latest_status_lists: BTreeMap::new(),
            sync_end_height: 0,
            is_synchronizing: false,
            block_lists: BTreeMap::new(),
            rand: thread_rng(),
            remote_sync_time_out: (Instant::now() - Duration::from_secs(SYNC_TIME_OUT)),
            local_sync_count: 0,
        }
    }

    /// After receiving the `Chain >> Status`, it is processed as follows:
    /// 1. The chain height suddenly becomes lower than the original,
    ///    which means that the library is deleted, that is,
    ///    the synchronization is restarted from the received height.
    /// 2. The height of the chain is greater than or equal to the original height,
    ///    less than or equal to the height that the network has synchronized
    ///        - It is equal to the original height more than 2 times, indicating that
    ///          the data in the chain or executor is lost, and the block information is
    ///          sent again from the buffer. If no buffer exists, the data is requested again from other nodes.
    /// 3. The height is greater than or equal to the global height, indicating that the synchronization
    ///     has been completed and the synchronization status is exited.
    /// 4. The height is less than the global height, indicating that synchronization needs to be continued
    /// 5. Other unknown state
    pub fn update_current_status(&mut self, latest_status: Status) {
        debug!(
            "sync: update_current_status: current height = {}, \
             before height = {}, \
             sync_end_height = {}",
            latest_status.get_height(),
            self.current_status.get_height(),
            self.sync_end_height
        );
        let old_height = self.current_status.get_height();
        let new_height = latest_status.get_height();

        if new_height == old_height {
            if self.local_sync_count < u8::MAX {
                // Chain height does not increase
                self.local_sync_count += 1;
            }
        } else {
            self.local_sync_count = 0;
            self.remote_sync_time_out = Instant::now();
        }

        self.latest_status_lists = self
            .latest_status_lists
            .split_off(&(latest_status.get_height() + 1));
        self.current_status = latest_status;
        self.broadcast_status();
        self.prune_block_list_cache(new_height + 1);

        info!(
            "current: {}, sync_end: {}, global: {}, sync: {}",
            new_height,
            self.sync_end_height,
            self.global_status.get_height(),
            self.is_synchronizing
        );

        if new_height < old_height {
            // Chain error, may be a problem with the database, such as the database was deleted
            let start_height = new_height + 1;

            if self.block_lists.contains_key(&start_height) && !self.block_lists.is_empty() {
                self.submit_blocks();
            } else {
                self.start_sync_req(start_height);
            }
        } else if new_height < self.sync_end_height {
            // In synchronization, or loss of sync data, need to resend
            debug!(
                "Syncing: update_current_status: height = {}, block_lists len = {}",
                new_height,
                self.block_lists.len()
            );

            if !self.block_lists.is_empty() && new_height < self.sync_end_height {
                if self.local_sync_count >= 3 {
                    // Chain height does not increase, loss data or data is invalid,
                    // send cache to executor and chain, and clear cache
                    self.local_sync_count = 0;
                    self.block_lists.clear();
                    self.start_sync_req(new_height + 1);
                    info!("More than 3 times, clear the cache");
                }
            }

            self.is_synchronizing = true;
        } else if new_height >= self.global_status.get_height() {
            if self.is_synchronizing {
                self.is_synchronizing = false;
                self.sync_end_height = 0;
                self.block_lists.clear();
            }
        } else if new_height < self.global_status.get_height() {
            // If the block height is equal to the maximum height that has already been synchronized,
            // perform the synchronization operation first to see if it is the latest in the chain
            if self.is_synchronizing {
                self.start_sync_req(new_height + 1);
            }
        } else {
            info!("...Can't reach this");
        }
    }

    /// 1. Global height is less than current height + 1, no action
    /// 2. Global height is equal to current height + 1
    ///     - Start syncing when it is not in sync and timeout
    /// 3. Global height is greater than current height + 1, Timeout or not in sync, initiate synchronization
    pub fn update_global_status(&mut self, status: &Status, origin: u32) {
        debug!(
            "sync: update_global_status: current height = {}, from node = {}, height = {}",
            self.current_status.get_height(),
            origin,
            status.get_height()
        );
        let current_height = self.current_status.get_height();
        if self.global_status.get_height() < status.get_height() {
            self.global_status = status.clone();
        }

        if status.get_height() < current_height + 1 {
            // The current node is the latest height and does not need to be synchronized
        } else if status.get_height() == current_height + 1 {
            // A node on the chain blocks out, synchronizing the latest block
            self.add_latest_sync_lists(status.get_height(), origin);

            if self.remote_sync_time_out.elapsed().as_secs() > SYNC_TIME_OUT
                && !self.is_synchronizing
            {
                self.start_sync_req(current_height + 1);
            }
        } else {
            // The node is far behind the data on the chain and initiates a synchronization request
            self.add_latest_sync_lists(status.get_height(), origin);

            if self.remote_sync_time_out.elapsed().as_secs() > SYNC_TIME_OUT
                || !self.is_synchronizing
            {
                self.start_sync_req(current_height + 1);
            }
        }
    }

    pub fn is_synchronizing(&self) -> bool {
        self.is_synchronizing
    }

    pub fn process_sync(&mut self, mut blocks: SyncResponse) {
        let blocks = blocks.take_blocks();
        debug!("sync: process_sync: blocks len = {}", blocks.len());

        let mut heights = vec![];
        for block in blocks.into_iter() {
            heights.push(block.get_header().get_height());
            self.block_lists
                .insert(block.get_header().get_height(), block);
        }

        debug!("sync: process_sync: heights = {:?}", heights);
        self.submit_blocks();
    }

    pub fn receive(&mut self, _from: Source, payload: (String, Vec<u8>)) {
        let (key, body) = payload;
        let mut msg = Message::try_from(&body).unwrap();
        let origin = msg.get_origin();
        match RoutingKey::from(&key) {
            routing_key!(Chain >> Status) => {
                if let Some(status) = msg.take_status() {
                    self.update_current_status(status);
                };
            }
            routing_key!(Synchronizer >> Status) => {
                if let Some(status) = msg.take_status() {
                    self.update_global_status(&status, origin);
                };
            }
            routing_key!(Synchronizer >> SyncResponse) => {
                if let Some(blocks) = msg.take_sync_response() {
                    self.process_sync(blocks);
                };
            }
            _ => {
                error!("receive: unexpected data key = {:?}", key);
            }
        }
    }

    // Initiate a sync request
    fn start_sync_req(&mut self, start_height: u64) {
        debug!(
            "sync: start_sync_req: start_height = {}, current height = {}",
            start_height,
            self.current_status.get_height()
        );
        let mut origin = 0;
        let mut end_height = start_height;
        let mut is_send = false;
        let current_height = self.current_status.get_height();

        if let Some((height, origins)) = self
            .latest_status_lists
            .iter()
            .rfind(|&(_, origins)| origins.len() > 0)
        {
            debug!(
                "sync: start_sync_req: height = {}, origins = {:?}",
                height, origins
            );
            if let Some(origins) = self.latest_status_lists.get(height) {
                if *height > current_height {
                    origin = origins[self.rand.gen_range(0, origins.len())];
                    end_height = if *height + 1 > current_height + SYNC_STEP {
                        current_height + SYNC_STEP
                    } else {
                        *height + 1
                    };
                    is_send = true;
                }
            }
        }

        if is_send {
            self.sync_strategy(start_height, end_height, origin);
        }
    }

    fn sync_strategy(&self, start_height: u64, end_height: u64, origin: u32) {
        //current height = 155,start_height = 156, end height = 160, to origin = 1
        debug!(
            "sync: sync_strategy: current height = {}, \
             start_height = {}, \
             end height = {}, \
             to origin = {}",
            self.current_status.get_height(),
            start_height,
            end_height,
            origin
        );
        if start_height >= self.current_status.get_height() && start_height <= end_height {
            let mut start_height = start_height;
            let mut step_sum = SYNC_STEP;
            let mut heights = vec![];

            while start_height <= end_height {
                if step_sum == 0 {
                    step_sum = SYNC_STEP;
                    self.send_sync_req(heights, origin);
                    heights = vec![];
                }
                heights.push(start_height);

                step_sum -= 1;
                start_height += 1;
            }
            self.send_sync_req(heights, origin);
        }
    }

    fn send_sync_req(&self, heights: Vec<u64>, origin: u32) {
        if !heights.is_empty() {
            debug!(
                "sync: send_sync_req:current height = {}, \
                 heights = {:?}, \
                 origin {:?}, \
                 chain.sync: OperateType {:?}",
                self.current_status.get_height(),
                heights,
                origin,
                OperateType::Single
            );
            let mut sync_req = SyncRequest::new();
            sync_req.set_heights(heights);
            let msg = Message::init(OperateType::Single, origin, sync_req.into());
            self.con
                .broadcast(routing_key!(Synchronizer >> SyncRequest).into(), msg);
        }
    }

    fn broadcast_status(&mut self) {
        debug!(
            "sync: broadcast status {:?}, {:?} to other nodes",
            self.current_status.get_height(),
            self.current_status.get_hash()
        );
        let msg: Message = self.current_status.clone().into();
        self.con
            .broadcast(routing_key!(Synchronizer >> Status).into(), msg);
    }

    // Submit synchronization information
    fn submit_blocks(&mut self) {
        let mut height = self.current_status.get_height() + 1;
        debug!(
            "sync: submit_blocks:submit_height = {},\
             current height = {},\
             sync_end_height = {},\
             block_lists = {}",
            height,
            self.current_status.get_height(),
            self.sync_end_height,
            self.block_lists.len()
        );
        let mut blocks = vec![];
        let end_height = height + SYNC_STEP;

        loop {
            if height <= end_height {
                if let Some(block) = self.block_lists.get(&height) {
                    blocks.push(block.to_owned());
                } else {
                    break;
                }
            } else {
                break;
            }
            height += 1;
        }

        match blocks.last() {
            Some(block) => {
                if let Some(header) = block.header.as_ref() {
                    let height = header.get_height() - 1;

                    if height > self.sync_end_height {
                        self.sync_end_height = height;
                    }
                }
            }
            None => {}
        }

        if self.block_lists.contains_key(&::std::u64::MAX) {
            blocks.push(self.block_lists.remove(&::std::u64::MAX).unwrap());
        }

        self.pub_blocks(blocks);
        self.is_synchronizing = true;
        self.remote_sync_time_out = Instant::now();
    }

    fn pub_blocks(&mut self, blocks: Vec<Block>) {
        if !blocks.is_empty() {
            debug!(
                "sync: pub_blocks: current height = {}, \
                 sync_end_height = {}, \
                 len = {}, ",
                self.current_status.get_height(),
                self.sync_end_height,
                blocks.len()
            );
            let mut sync_res = SyncResponse::new();
            sync_res.set_blocks(blocks.into());
            let msg: Message = sync_res.into();
            self.tx_pub.send((
                routing_key!(Net >> SyncResponse).into(),
                msg.try_into().unwrap(),
            ));
        }
    }

    fn add_latest_sync_lists(&mut self, height: u64, origin: u32) {
        debug!(
            "sync: add_sync_lists: current height = {}, \
             from node = {}, \
             height = {}",
            self.current_status.get_height(),
            origin,
            height
        );
        if self
            .latest_status_lists
            .entry(height)
            .or_insert_with(VecDeque::new)
            .iter()
            .fold(HashSet::new(), |mut set, item| {
                set.insert(item);
                set
            })
            .insert(&origin)
        {
            self.latest_status_lists
                .entry(height)
                .or_insert_with(VecDeque::new)
                .push_back(origin);
        }
    }

    /// Prune block on btreemap
    fn prune_block_list_cache(&mut self, height: u64) {
        self.block_lists = self.block_lists.split_off(&height);
    }
}
<commit_msg>modify sync request start height<commit_after>use connection::Connection;
use libproto::blockchain::{Block, Status};
use libproto::router::{MsgType, RoutingKey, SubModules};
use libproto::{Message, OperateType, SyncRequest, SyncResponse};
use rand::{thread_rng, Rng, ThreadRng};
use std::collections::{BTreeMap, HashSet, VecDeque};
use std::convert::{Into, TryFrom, TryInto};
use std::sync::{mpsc, Arc};
use std::time::{Duration, Instant};
use std::u8;
use Source;

const SYNC_STEP: u64 = 20;
const SYNC_TIME_OUT: u64 = 9;

/// Get messages and determine if need to synchronize or broadcast the current node status
pub struct Synchronizer {
    tx_pub: mpsc::Sender<(String, Vec<u8>)>,
    con: Arc<Connection>,
    current_status: Status,
    global_status: Status,
    sync_end_height: u64, //current_status <= sync_end_status
    is_synchronizing: bool,
    latest_status_lists: BTreeMap<u64, VecDeque<u32>>,
    block_lists: BTreeMap<u64, Block>,
    rand: ThreadRng,
    // Timer for each height processing
    remote_sync_time_out: Instant,
    /// local sync error
    local_sync_count: u8,
}

unsafe impl Sync for Synchronizer {}
unsafe impl Send for Synchronizer {}

impl Synchronizer {
    pub fn new(tx_pub: mpsc::Sender<(String, Vec<u8>)>, con: Arc<Connection>) -> Self {
        Synchronizer {
            tx_pub: tx_pub,
            con: con,
            current_status: Status::new(),
            global_status: Status::new(),
            latest_status_lists: BTreeMap::new(),
            sync_end_height: 0,
            is_synchronizing: false,
            block_lists: BTreeMap::new(),
            rand: thread_rng(),
            remote_sync_time_out: (Instant::now() - Duration::from_secs(SYNC_TIME_OUT)),
            local_sync_count: 0,
        }
    }

    /// After receiving the `Chain >> Status`, it is processed as follows:
    /// 1. The chain height suddenly becomes lower than the original,
    ///    which means that the library is deleted, that is,
    ///    the synchronization is restarted from the received height.
    /// 2. The height of the chain is greater than or equal to the original height,
    ///    less than or equal to the height that the network has synchronized
    ///        - It is equal to the original height more than 2 times, indicating that
    ///          the data in the chain or executor is lost, and the block information is
    ///          sent again from the buffer. If no buffer exists, the data is requested again from other nodes.
    /// 3. The height is greater than or equal to the global height, indicating that the synchronization
    ///     has been completed and the synchronization status is exited.
    /// 4. The height is less than the global height, indicating that synchronization needs to be continued
    /// 5. Other unknown state
    pub fn update_current_status(&mut self, latest_status: Status) {
        debug!(
            "sync: update_current_status: current height = {}, \
             before height = {}, \
             sync_end_height = {}",
            latest_status.get_height(),
            self.current_status.get_height(),
            self.sync_end_height
        );
        let old_height = self.current_status.get_height();
        let new_height = latest_status.get_height();

        if new_height == old_height {
            if self.local_sync_count < u8::MAX {
                // Chain height does not increase
                self.local_sync_count += 1;
            }
        } else {
            self.local_sync_count = 0;
            self.remote_sync_time_out = Instant::now();
        }

        self.latest_status_lists = self
            .latest_status_lists
            .split_off(&(latest_status.get_height() + 1));
        self.current_status = latest_status;
        self.broadcast_status();
        self.prune_block_list_cache(new_height + 1);

        info!(
            "current: {}, sync_end: {}, global: {}, sync: {}",
            new_height,
            self.sync_end_height,
            self.global_status.get_height(),
            self.is_synchronizing
        );

        if new_height < old_height {
            // Chain error, may be a problem with the database, such as the database was deleted
            let start_height = new_height + 1;

            if self.block_lists.contains_key(&start_height) && !self.block_lists.is_empty() {
                self.submit_blocks();
            } else {
                self.start_sync_req(start_height);
            }
        } else if new_height < self.sync_end_height {
            // In synchronization, or loss of sync data, need to resend
            debug!(
                "Syncing: update_current_status: height = {}, block_lists len = {}",
                new_height,
                self.block_lists.len()
            );

            if !self.block_lists.is_empty() && new_height < self.sync_end_height {
                if self.local_sync_count >= 3 {
                    // Chain height does not increase, loss data or data is invalid,
                    // send cache to executor and chain, and clear cache
                    self.local_sync_count = 0;
                    self.block_lists.clear();
                    self.start_sync_req(new_height + 1);
                    info!("More than 3 times, clear the cache");
                }
            }

            self.is_synchronizing = true;
        } else if new_height >= self.global_status.get_height() {
            if self.is_synchronizing {
                self.is_synchronizing = false;
                self.sync_end_height = 0;
                self.block_lists.clear();
            }
        } else if new_height < self.global_status.get_height() {
            // If the block height is equal to the maximum height that has already been synchronized,
            // perform the synchronization operation first to see if it is the latest in the chain
            if self.is_synchronizing {
                let start = match self.block_lists.iter().last() {
                    Some((height, _)) => *height + 1,
                    None => new_height + 1,
                };
                self.start_sync_req(start);
            }
        } else {
            info!("...Can't reach this");
        }
    }

    /// 1. Global height is less than current height + 1, no action
    /// 2. Global height is equal to current height + 1
    ///     - Start syncing when it is not in sync and timeout
    /// 3. Global height is greater than current height + 1, Timeout or not in sync, initiate synchronization
    pub fn update_global_status(&mut self, status: &Status, origin: u32) {
        debug!(
            "sync: update_global_status: current height = {}, from node = {}, height = {}",
            self.current_status.get_height(),
            origin,
            status.get_height()
        );
        let current_height = self.current_status.get_height();
        if self.global_status.get_height() < status.get_height() {
            self.global_status = status.clone();
        }

        if status.get_height() < current_height + 1 {
            // The current node is the latest height and does not need to be synchronized
        } else if status.get_height() == current_height + 1 {
            // A node on the chain blocks out, synchronizing the latest block
            self.add_latest_sync_lists(status.get_height(), origin);

            if self.remote_sync_time_out.elapsed().as_secs() > SYNC_TIME_OUT
                && !self.is_synchronizing
            {
                self.start_sync_req(current_height + 1);
            }
        } else {
            // The node is far behind the data on the chain and initiates a synchronization request
            self.add_latest_sync_lists(status.get_height(), origin);

            if self.remote_sync_time_out.elapsed().as_secs() > SYNC_TIME_OUT
                || !self.is_synchronizing
            {
                self.start_sync_req(current_height + 1);
            }
        }
    }

    pub fn is_synchronizing(&self) -> bool {
        self.is_synchronizing
    }

    pub fn process_sync(&mut self, mut blocks: SyncResponse) {
        let blocks = blocks.take_blocks();
        debug!("sync: process_sync: blocks len = {}", blocks.len());

        let mut heights = vec![];
        for block in blocks.into_iter() {
            heights.push(block.get_header().get_height());
            self.block_lists
                .insert(block.get_header().get_height(), block);
        }

        debug!("sync: process_sync: heights = {:?}", heights);
        self.submit_blocks();
    }

    pub fn receive(&mut self, _from: Source, payload: (String, Vec<u8>)) {
        let (key, body) = payload;
        let mut msg = Message::try_from(&body).unwrap();
        let origin = msg.get_origin();
        match RoutingKey::from(&key) {
            routing_key!(Chain >> Status) => {
                if let Some(status) = msg.take_status() {
                    self.update_current_status(status);
                };
            }
            routing_key!(Synchronizer >> Status) => {
                if let Some(status) = msg.take_status() {
                    self.update_global_status(&status, origin);
                };
            }
            routing_key!(Synchronizer >> SyncResponse) => {
                if let Some(blocks) = msg.take_sync_response() {
                    self.process_sync(blocks);
                };
            }
            _ => {
                error!("receive: unexpected data key = {:?}", key);
            }
        }
    }

    // Initiate a sync request
    fn start_sync_req(&mut self, start_height: u64) {
        debug!(
            "sync: start_sync_req: start_height = {}, current height = {}",
            start_height,
            self.current_status.get_height()
        );
        let mut origin = 0;
        let mut end_height = start_height;
        let mut is_send = false;
        let current_height = self.current_status.get_height();

        if let Some((height, origins)) = self
            .latest_status_lists
            .iter()
            .rfind(|&(_, origins)| origins.len() > 0)
        {
            debug!(
                "sync: start_sync_req: height = {}, origins = {:?}",
                height, origins
            );
            if let Some(origins) = self.latest_status_lists.get(height) {
                if *height > current_height {
                    origin = origins[self.rand.gen_range(0, origins.len())];
                    end_height = if *height + 1 > current_height + SYNC_STEP {
                        current_height + SYNC_STEP
                    } else {
                        *height + 1
                    };
                    is_send = true;
                }
            }
        }

        if is_send {
            self.sync_strategy(start_height, end_height, origin);
        }
    }

    fn sync_strategy(&self, start_height: u64, end_height: u64, origin: u32) {
        //current height = 155,start_height = 156, end height = 160, to origin = 1
        debug!(
            "sync: sync_strategy: current height = {}, \
             start_height = {}, \
             end height = {}, \
             to origin = {}",
            self.current_status.get_height(),
            start_height,
            end_height,
            origin
        );
        if start_height >= self.current_status.get_height() && start_height <= end_height {
            let mut start_height = start_height;
            let mut step_sum = SYNC_STEP;
            let mut heights = vec![];

            while start_height <= end_height {
                if step_sum == 0 {
                    step_sum = SYNC_STEP;
                    self.send_sync_req(heights, origin);
                    heights = vec![];
                }
                heights.push(start_height);

                step_sum -= 1;
                start_height += 1;
            }
            self.send_sync_req(heights, origin);
        }
    }

    fn send_sync_req(&self, heights: Vec<u64>, origin: u32) {
        if !heights.is_empty() {
            debug!(
                "sync: send_sync_req:current height = {}, \
                 heights = {:?}, \
                 origin {:?}, \
                 chain.sync: OperateType {:?}",
                self.current_status.get_height(),
                heights,
                origin,
                OperateType::Single
            );
            let mut sync_req = SyncRequest::new();
            sync_req.set_heights(heights);
            let msg = Message::init(OperateType::Single, origin, sync_req.into());
            self.con
                .broadcast(routing_key!(Synchronizer >> SyncRequest).into(), msg);
        }
    }

    fn broadcast_status(&mut self) {
        debug!(
            "sync: broadcast status {:?}, {:?} to other nodes",
            self.current_status.get_height(),
            self.current_status.get_hash()
        );
        let msg: Message = self.current_status.clone().into();
        self.con
            .broadcast(routing_key!(Synchronizer >> Status).into(), msg);
    }

    // Submit synchronization information
    fn submit_blocks(&mut self) {
        let mut height = self.current_status.get_height() + 1;
        debug!(
            "sync: submit_blocks:submit_height = {},\
             current height = {},\
             sync_end_height = {},\
             block_lists = {}",
            height,
            self.current_status.get_height(),
            self.sync_end_height,
            self.block_lists.len()
        );
        let mut blocks = vec![];
        let end_height = height + SYNC_STEP;

        loop {
            if height <= end_height {
                if let Some(block) = self.block_lists.get(&height) {
                    blocks.push(block.to_owned());
                } else {
                    break;
                }
            } else {
                break;
            }
            height += 1;
        }

        match blocks.last() {
            Some(block) => {
                if let Some(header) = block.header.as_ref() {
                    let height = header.get_height() - 1;

                    if height > self.sync_end_height {
                        self.sync_end_height = height;
                    }
                }
            }
            None => {}
        }

        if self.block_lists.contains_key(&::std::u64::MAX) {
            blocks.push(self.block_lists.remove(&::std::u64::MAX).unwrap());
        }

        self.pub_blocks(blocks);
        self.is_synchronizing = true;
        self.remote_sync_time_out = Instant::now();
    }

    fn pub_blocks(&mut self, blocks: Vec<Block>) {
        if !blocks.is_empty() {
            debug!(
                "sync: pub_blocks: current height = {}, \
                 sync_end_height = {}, \
                 len = {}, ",
                self.current_status.get_height(),
                self.sync_end_height,
                blocks.len()
            );
            let mut sync_res = SyncResponse::new();
            sync_res.set_blocks(blocks.into());
            let msg: Message = sync_res.into();
            self.tx_pub.send((
                routing_key!(Net >> SyncResponse).into(),
                msg.try_into().unwrap(),
            ));
        }
    }

    fn add_latest_sync_lists(&mut self, height: u64, origin: u32) {
        debug!(
            "sync: add_sync_lists: current height = {}, \
             from node = {}, \
             height = {}",
            self.current_status.get_height(),
            origin,
            height
        );
        if self
            .latest_status_lists
            .entry(height)
            .or_insert_with(VecDeque::new)
            .iter()
            .fold(HashSet::new(), |mut set, item| {
                set.insert(item);
                set
            })
            .insert(&origin)
        {
            self.latest_status_lists
                .entry(height)
                .or_insert_with(VecDeque::new)
                .push_back(origin);
        }
    }

    /// Prune block on btreemap
    fn prune_block_list_cache(&mut self, height: u64) {
        self.block_lists = self.block_lists.split_off(&height);
    }
}
<|endoftext|>


<commit_before>extern crate getopts;
extern crate miri;
extern crate rustc;
extern crate rustc_driver;
extern crate test;

use self::miri::eval_main;
use self::rustc_driver::{driver, Compilation};
use std::cell::RefCell;
use std::rc::Rc;
use crate::test::Bencher;

pub struct MiriCompilerCalls<'a>(Rc<RefCell<&'a mut Bencher>>);

fn find_sysroot() -> String {
    // Taken from https://github.com/Manishearth/rust-clippy/pull/911.
    let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME"));
    let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN"));
    match (home, toolchain) {
        (Some(home), Some(toolchain)) => format!("{}/toolchains/{}", home, toolchain),
        _ => {
            option_env!("RUST_SYSROOT")
                .expect(
                    "need to specify RUST_SYSROOT env var or use rustup or multirust",
                )
                .to_owned()
        }
    }
}

pub fn run(filename: &str, bencher: &mut Bencher) {
    let args = &[
        "miri".to_string(),
        format!("benches/helpers/{}.rs", filename),
        "--sysroot".to_string(),
        find_sysroot(),
    ];
    let bencher = RefCell::new(bencher);

    let mut control = driver::CompileController::basic();

    control.after_analysis.stop = Compilation::Stop;
    control.after_analysis.callback = Box::new(move |state| {
        state.session.abort_if_errors();

        let tcx = state.tcx.unwrap();
        let (entry_node_id, _, _) = state.session.entry_fn.borrow().expect(
            "no main or start function found",
        );
        let entry_def_id = tcx.hir.local_def_id(entry_node_id);

        bencher.borrow_mut().iter(|| {
            eval_main(tcx, entry_def_id, false);
        });

        state.session.abort_if_errors();
    });

    rustc_driver::run_compiler(args, Box::new(control), None, None);
}
<commit_msg>fix benches<commit_after>extern crate getopts;
extern crate miri;
extern crate rustc;
extern crate rustc_driver;
extern crate test;

use self::miri::eval_main;
use self::rustc_driver::{driver, Compilation};
use std::cell::RefCell;
use std::rc::Rc;
use crate::test::Bencher;

pub struct MiriCompilerCalls<'a>(Rc<RefCell<&'a mut Bencher>>);

fn find_sysroot() -> String {
    // Taken from https://github.com/Manishearth/rust-clippy/pull/911.
    let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME"));
    let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN"));
    match (home, toolchain) {
        (Some(home), Some(toolchain)) => format!("{}/toolchains/{}", home, toolchain),
        _ => {
            option_env!("RUST_SYSROOT")
                .expect(
                    "need to specify RUST_SYSROOT env var or use rustup or multirust",
                )
                .to_owned()
        }
    }
}

pub fn run(filename: &str, bencher: &mut Bencher) {
    let args = &[
        "miri".to_string(),
        format!("benches/helpers/{}.rs", filename),
        "--sysroot".to_string(),
        find_sysroot(),
    ];
    let bencher = RefCell::new(bencher);

    let mut control = driver::CompileController::basic();

    control.after_analysis.stop = Compilation::Stop;
    control.after_analysis.callback = Box::new(move |state| {
        state.session.abort_if_errors();

        let tcx = state.tcx.unwrap();
        let (entry_node_id, _, _) = state.session.entry_fn.borrow().expect(
            "no main or start function found",
        );
        let entry_def_id = tcx.hir().local_def_id(entry_node_id);

        bencher.borrow_mut().iter(|| {
            eval_main(tcx, entry_def_id, false);
        });

        state.session.abort_if_errors();
    });

    rustc_driver::run_compiler(args, Box::new(control), None, None);
}
<|endoftext|>


<commit_before>// Copyright (c) 2014 by SiegeLord
//
// All rights reserved. Distributed under ZLib. For full terms see the file LICENSE.

use allegro::c_bool;

use libc::*;
use sync::Arc;
use std::mem;
use std::ptr;
use std::option::Some;
use std::sync::atomics::{AtomicBool, SeqCst};
use std::raw::Slice;

use mixer::AttachToMixer;
use ffi::*;
use internal::{Connection, AttachToMixerImpl};
use properties::*;

pub trait DataSample
{
	fn get_depth(_: Option<Self>) -> AudioDepth;
}

macro_rules! data_sample_impl
{
	($t: ty, $d: ident) =>
	{
		impl DataSample for $t
		{
			fn get_depth(_: Option<$t>) -> AudioDepth
			{
				$d
			}
		}
	}
}

data_sample_impl!(i8, AudioDepthI8)
data_sample_impl!(i16, AudioDepthI16)
data_sample_impl!(u8, AudioDepthU8)
data_sample_impl!(u16, AudioDepthU16)
data_sample_impl!(f32, AudioDepthF32)

// TODO: ALLEGRO_SAMPLE and ALLEGRO_SAMPLE_INSTANCE can probably race on each other...
// consider adding mutexes (maybe Allegro's mutexes prevent everything bad already)

pub struct Sample
{
	allegro_sample: *mut ALLEGRO_SAMPLE,
	// This will inform sample instances that this sample got dropped
	sample_valid: Arc<AtomicBool>,
}

impl Sample
{
	fn load(filename: &str) -> Option<Sample>
	{
		let samp = filename.with_c_str(|s|
		{
			unsafe
			{
				al_load_sample(s)
			}
		});
		if samp.is_null()
		{
			None
		}
		else
		{
			Some(Sample
			{
				allegro_sample: samp,
				sample_valid: Arc::new(AtomicBool::new(true))
			})
		}
	}

	pub fn create_instance(&self) -> Option<SampleInstance>
	{
		let mut inst = SampleInstance::new();
		inst.as_mut().map(|inst|
		{
			inst.set_sample(self);
		});
		inst
	}

	pub fn get_frequency(&self) -> uint
	{
		unsafe
		{
			al_get_sample_frequency(self.allegro_sample as *const ALLEGRO_SAMPLE) as uint
		}
	}

	pub fn get_length(&self) -> uint
	{
		unsafe
		{
			al_get_sample_length(self.allegro_sample as *const ALLEGRO_SAMPLE) as uint
		}
	}

	pub fn get_byte_length(&self) -> uint
	{
		self.get_length() * self.get_channels().get_num_channels() * self.get_depth().get_byte_size()
	}

	pub fn get_depth(&self) -> AudioDepth
	{
		unsafe
		{
			AudioDepth::from_allegro(al_get_sample_depth(self.allegro_sample as *const ALLEGRO_SAMPLE))
		}
	}

	pub fn get_channels(&self) -> ChannelConf
	{
		unsafe
		{
			ChannelConf::from_allegro(al_get_sample_channels(self.allegro_sample as *const ALLEGRO_SAMPLE))
		}
	}

	pub fn get_raw_data<'l>(&'l self) -> &'l [u8]
	{
		let len = self.get_byte_length();
		unsafe
		{
			mem::transmute(Slice{ data: al_get_sample_data(self.allegro_sample as *const ALLEGRO_SAMPLE) as *const u8, len: len })
		}
	}

	pub fn get_data<'l, T: DataSample>(&'l self) -> Option<&'l [T]>
	{
		if self.get_depth() == DataSample::get_depth(None::<T>)
		{
			let len = self.get_byte_length() / mem::size_of::<T>();
			Some(unsafe
			{
				mem::transmute(Slice{ data: al_get_sample_data(self.allegro_sample as *const ALLEGRO_SAMPLE) as *const u8, len: len })
			})
		}
		else
		{
			None
		}
	}

	pub fn get_data_mut<'l, T: DataSample>(&'l mut self) -> Option<&'l mut [T]>
	{
		if self.get_depth() == DataSample::get_depth(None::<T>)
		{
			let len = self.get_byte_length() / mem::size_of::<T>();
			Some(unsafe
			{
				mem::transmute(Slice{ data: al_get_sample_data(self.allegro_sample as *const ALLEGRO_SAMPLE) as *const u8, len: len })
			})
		}
		else
		{
			None
		}
	}

	pub fn get_raw_data_mut<'l>(&'l mut self) -> &'l mut [u8]
	{
		let len = self.get_byte_length();
		unsafe
		{
			mem::transmute(Slice{ data: al_get_sample_data(self.allegro_sample as *const ALLEGRO_SAMPLE) as *const u8, len: len })
		}
	}

	pub fn get_allegro_sample(&self) -> *mut ALLEGRO_SAMPLE
	{
		self.allegro_sample
	}
}

impl Drop for Sample
{
	fn drop(&mut self)
	{
		self.sample_valid.swap(false, SeqCst);
		unsafe
		{
			al_destroy_sample(self.allegro_sample);
		}
	}
}

pub struct SampleInstance
{
	parent: Option<Connection>,
	// I think when the sample is invalid, it is unsafe to resume it
	sample_valid: Arc<AtomicBool>,
	allegro_sample_instance: *mut ALLEGRO_SAMPLE_INSTANCE,
}

macro_rules! check_or_else
{
	($valid: expr, $invalid: expr) =>
	{
		if self.sample_valid.load(SeqCst)
		{
			unsafe
			{
				$valid
			}
		}
		else
		{
			$invalid
		}
	}
}

macro_rules! set_impl
{
	($c_func: ident, $var: expr) =>
	{
		check_or_else!($c_func(self.allegro_sample_instance, $var) != 0, false)
	}
}

macro_rules! get_opt_impl
{
	($c_func: ident, $dest_ty: ty) =>
	{
		check_or_else!(Some($c_func(self.allegro_sample_instance as *const ALLEGRO_SAMPLE_INSTANCE) as $dest_ty), None)
	}
}

macro_rules! get_conv_impl
{
	($c_func: ident, $conv: path) =>
	{
		check_or_else!(Some($conv($c_func(self.allegro_sample_instance as *const ALLEGRO_SAMPLE_INSTANCE))), None)
	}
}

macro_rules! get_bool_impl
{
	($c_func: ident) =>
	{
		check_or_else!($c_func(self.allegro_sample_instance as *const ALLEGRO_SAMPLE_INSTANCE) != 0, false)
	}
}

impl SampleInstance
{
	fn new() -> Option<SampleInstance>
	{
		let inst = unsafe { al_create_sample_instance(ptr::mut_null()) };
		if inst.is_null()
		{
			None
		}
		else
		{
			Some(SampleInstance
			{
				parent: None,
				sample_valid: Arc::new(AtomicBool::new(false)),
				allegro_sample_instance: inst
			})
		}
	}

	fn detach(allegro_sample_instance: *mut c_void)
	{
		unsafe
		{
			al_detach_sample_instance(mem::transmute(allegro_sample_instance));
		}
	}

	pub fn set_sample(&mut self, sample: &Sample) -> bool
	{
		if unsafe { al_set_sample(self.allegro_sample_instance, sample.allegro_sample) != 0 }
		{
			self.sample_valid = sample.sample_valid.clone();
			true
		}
		else
		{
			self.sample_valid = Arc::new(AtomicBool::new(false));
			// As per docs of al_set_sample
			self.parent = None;
			false
		}
	}

	pub fn set_position(&self, position: u32) -> bool
	{
		set_impl!(al_set_sample_instance_position, position as c_uint)
	}

	pub fn set_length(&self, length: u32) -> bool
	{
		set_impl!(al_set_sample_instance_length, length as c_uint)
	}

	pub fn set_playing(&self, playing: bool) -> bool
	{
		set_impl!(al_set_sample_instance_playing, playing as c_bool)
	}

	pub fn set_gain(&self, gain: f32) -> bool
	{
		set_impl!(al_set_sample_instance_gain, gain as c_float)
	}

	pub fn set_pan(&self, pan: Option<f32>) -> bool
	{
		set_impl!(al_set_sample_instance_pan,
		match pan
		{
			Some(p) => p as c_float,
			None => ALLEGRO_AUDIO_PAN_NONE
		})
	}

	pub fn set_speed(&self, speed: f32) -> bool
	{
		set_impl!(al_set_sample_instance_speed, speed as c_float)
	}

	pub fn set_playmode(&self, playmode: Playmode) -> bool
	{
		set_impl!(al_set_sample_instance_playmode, playmode.get())
	}

	pub fn get_frequency(&self) -> Option<u32>
	{
		get_opt_impl!(al_get_sample_instance_frequency, u32)
	}

	pub fn get_length(&self) -> Option<u32>
	{
		get_opt_impl!(al_get_sample_instance_length, u32)
	}

	pub fn get_position(&self) -> Option<u32>
	{
		get_opt_impl!(al_get_sample_instance_position, u32)
	}

	pub fn get_speed(&self) -> Option<f32>
	{
		get_opt_impl!(al_get_sample_instance_speed, f32)
	}

	pub fn get_gain(&self) -> Option<f32>
	{
		get_opt_impl!(al_get_sample_instance_gain, f32)
	}

	pub fn get_pan(&self) -> Option<f32>
	{
		get_opt_impl!(al_get_sample_instance_pan, f32)
	}

	pub fn get_time(&self) -> Option<f32>
	{
		get_opt_impl!(al_get_sample_instance_time, f32)
	}

	pub fn get_playmode(&self) -> Option<Playmode>
	{
		get_conv_impl!(al_get_sample_instance_playmode, Playmode::from_allegro)
	}

	pub fn get_channels(&self) -> Option<ChannelConf>
	{
		get_conv_impl!(al_get_sample_instance_channels, ChannelConf::from_allegro)
	}

	pub fn get_depth(&self) -> Option<AudioDepth>
	{
		get_conv_impl!(al_get_sample_instance_depth, AudioDepth::from_allegro)
	}

	pub fn get_playing(&self) -> bool
	{
		get_bool_impl!(al_get_sample_instance_playing)
	}

	pub fn get_attached(&self) -> bool
	{
		get_bool_impl!(al_get_sample_instance_attached)
	}

	pub fn get_allegro_sample_instance(&self) -> *mut ALLEGRO_SAMPLE_INSTANCE
	{
		self.allegro_sample_instance
	}
}

impl Drop for SampleInstance
{
	fn drop(&mut self)
	{
		self.detach();
		unsafe
		{
			al_destroy_sample_instance(self.allegro_sample_instance);
		}
	}
}

impl AttachToMixerImpl for SampleInstance
{
	fn create_connection(&mut self, allegro_mixer: *mut ALLEGRO_MIXER) -> Option<Connection>
	{
		if unsafe{ al_attach_sample_instance_to_mixer(self.allegro_sample_instance, allegro_mixer) == 0 }
		{
			None
		}
		else
		{
			let (c1, c2) = Connection::new(unsafe{ mem::transmute(self.allegro_sample_instance) }, SampleInstance::detach);
			self.parent = Some(c1);
			Some(c2)
		}
	}
}

impl AttachToMixer for SampleInstance
{
	fn detach(&mut self)
	{
		self.parent = None;
	}
}

impl ::addon::AudioAddon
{
	pub fn create_sample_instance(&self) -> Option<SampleInstance>
	{
		SampleInstance::new()
	}

	pub fn load_sample(&self, filename: &str) -> Option<Sample>
	{
		Sample::load(filename)
	}
}
<commit_msg>I hate macro hygiene<commit_after>// Copyright (c) 2014 by SiegeLord
//
// All rights reserved. Distributed under ZLib. For full terms see the file LICENSE.

use allegro::c_bool;

use libc::*;
use sync::Arc;
use std::mem;
use std::ptr;
use std::option::Some;
use std::sync::atomics::{AtomicBool, SeqCst};
use std::raw::Slice;

use mixer::AttachToMixer;
use ffi::*;
use internal::{Connection, AttachToMixerImpl};
use properties::*;

pub trait DataSample
{
	fn get_depth(_: Option<Self>) -> AudioDepth;
}

macro_rules! data_sample_impl
{
	($t: ty, $d: ident) =>
	{
		impl DataSample for $t
		{
			fn get_depth(_: Option<$t>) -> AudioDepth
			{
				$d
			}
		}
	}
}

data_sample_impl!(i8, AudioDepthI8)
data_sample_impl!(i16, AudioDepthI16)
data_sample_impl!(u8, AudioDepthU8)
data_sample_impl!(u16, AudioDepthU16)
data_sample_impl!(f32, AudioDepthF32)

// TODO: ALLEGRO_SAMPLE and ALLEGRO_SAMPLE_INSTANCE can probably race on each other...
// consider adding mutexes (maybe Allegro's mutexes prevent everything bad already)

pub struct Sample
{
	allegro_sample: *mut ALLEGRO_SAMPLE,
	// This will inform sample instances that this sample got dropped
	sample_valid: Arc<AtomicBool>,
}

impl Sample
{
	fn load(filename: &str) -> Option<Sample>
	{
		let samp = filename.with_c_str(|s|
		{
			unsafe
			{
				al_load_sample(s)
			}
		});
		if samp.is_null()
		{
			None
		}
		else
		{
			Some(Sample
			{
				allegro_sample: samp,
				sample_valid: Arc::new(AtomicBool::new(true))
			})
		}
	}

	pub fn create_instance(&self) -> Option<SampleInstance>
	{
		let mut inst = SampleInstance::new();
		inst.as_mut().map(|inst|
		{
			inst.set_sample(self);
		});
		inst
	}

	pub fn get_frequency(&self) -> uint
	{
		unsafe
		{
			al_get_sample_frequency(self.allegro_sample as *const ALLEGRO_SAMPLE) as uint
		}
	}

	pub fn get_length(&self) -> uint
	{
		unsafe
		{
			al_get_sample_length(self.allegro_sample as *const ALLEGRO_SAMPLE) as uint
		}
	}

	pub fn get_byte_length(&self) -> uint
	{
		self.get_length() * self.get_channels().get_num_channels() * self.get_depth().get_byte_size()
	}

	pub fn get_depth(&self) -> AudioDepth
	{
		unsafe
		{
			AudioDepth::from_allegro(al_get_sample_depth(self.allegro_sample as *const ALLEGRO_SAMPLE))
		}
	}

	pub fn get_channels(&self) -> ChannelConf
	{
		unsafe
		{
			ChannelConf::from_allegro(al_get_sample_channels(self.allegro_sample as *const ALLEGRO_SAMPLE))
		}
	}

	pub fn get_raw_data<'l>(&'l self) -> &'l [u8]
	{
		let len = self.get_byte_length();
		unsafe
		{
			mem::transmute(Slice{ data: al_get_sample_data(self.allegro_sample as *const ALLEGRO_SAMPLE) as *const u8, len: len })
		}
	}

	pub fn get_data<'l, T: DataSample>(&'l self) -> Option<&'l [T]>
	{
		if self.get_depth() == DataSample::get_depth(None::<T>)
		{
			let len = self.get_byte_length() / mem::size_of::<T>();
			Some(unsafe
			{
				mem::transmute(Slice{ data: al_get_sample_data(self.allegro_sample as *const ALLEGRO_SAMPLE) as *const u8, len: len })
			})
		}
		else
		{
			None
		}
	}

	pub fn get_data_mut<'l, T: DataSample>(&'l mut self) -> Option<&'l mut [T]>
	{
		if self.get_depth() == DataSample::get_depth(None::<T>)
		{
			let len = self.get_byte_length() / mem::size_of::<T>();
			Some(unsafe
			{
				mem::transmute(Slice{ data: al_get_sample_data(self.allegro_sample as *const ALLEGRO_SAMPLE) as *const u8, len: len })
			})
		}
		else
		{
			None
		}
	}

	pub fn get_raw_data_mut<'l>(&'l mut self) -> &'l mut [u8]
	{
		let len = self.get_byte_length();
		unsafe
		{
			mem::transmute(Slice{ data: al_get_sample_data(self.allegro_sample as *const ALLEGRO_SAMPLE) as *const u8, len: len })
		}
	}

	pub fn get_allegro_sample(&self) -> *mut ALLEGRO_SAMPLE
	{
		self.allegro_sample
	}
}

impl Drop for Sample
{
	fn drop(&mut self)
	{
		self.sample_valid.swap(false, SeqCst);
		unsafe
		{
			al_destroy_sample(self.allegro_sample);
		}
	}
}

pub struct SampleInstance
{
	parent: Option<Connection>,
	// I think when the sample is invalid, it is unsafe to resume it
	sample_valid: Arc<AtomicBool>,
	allegro_sample_instance: *mut ALLEGRO_SAMPLE_INSTANCE,
}

macro_rules! check_or_else
{
	($self_: ident, $valid: expr, $invalid: expr) =>
	{
		if $self_.sample_valid.load(SeqCst)
		{
			unsafe
			{
				$valid
			}
		}
		else
		{
			$invalid
		}
	}
}

macro_rules! set_impl
{
	($self_: ident, $c_func: ident, $var: expr) =>
	{
		check_or_else!($self_, $c_func($self_.allegro_sample_instance, $var) != 0, false)
	}
}

macro_rules! get_opt_impl
{
	($self_: ident,$c_func: ident, $dest_ty: ty) =>
	{
		check_or_else!($self_, Some($c_func($self_.allegro_sample_instance as *const ALLEGRO_SAMPLE_INSTANCE) as $dest_ty), None)
	}
}

macro_rules! get_conv_impl
{
	($self_: ident,$c_func: ident, $conv: path) =>
	{
		check_or_else!($self_, Some($conv($c_func($self_.allegro_sample_instance as *const ALLEGRO_SAMPLE_INSTANCE))), None)
	}
}

macro_rules! get_bool_impl
{
	($self_: ident,$c_func: ident) =>
	{
		check_or_else!($self_, $c_func($self_.allegro_sample_instance as *const ALLEGRO_SAMPLE_INSTANCE) != 0, false)
	}
}

impl SampleInstance
{
	fn new() -> Option<SampleInstance>
	{
		let inst = unsafe { al_create_sample_instance(ptr::mut_null()) };
		if inst.is_null()
		{
			None
		}
		else
		{
			Some(SampleInstance
			{
				parent: None,
				sample_valid: Arc::new(AtomicBool::new(false)),
				allegro_sample_instance: inst
			})
		}
	}

	fn detach(allegro_sample_instance: *mut c_void)
	{
		unsafe
		{
			al_detach_sample_instance(mem::transmute(allegro_sample_instance));
		}
	}

	pub fn set_sample(&mut self, sample: &Sample) -> bool
	{
		if unsafe { al_set_sample(self.allegro_sample_instance, sample.allegro_sample) != 0 }
		{
			self.sample_valid = sample.sample_valid.clone();
			true
		}
		else
		{
			self.sample_valid = Arc::new(AtomicBool::new(false));
			// As per docs of al_set_sample
			self.parent = None;
			false
		}
	}

	pub fn set_position(&self, position: u32) -> bool
	{
		set_impl!(self, al_set_sample_instance_position, position as c_uint)
	}

	pub fn set_length(&self, length: u32) -> bool
	{
		set_impl!(self, al_set_sample_instance_length, length as c_uint)
	}

	pub fn set_playing(&self, playing: bool) -> bool
	{
		set_impl!(self, al_set_sample_instance_playing, playing as c_bool)
	}

	pub fn set_gain(&self, gain: f32) -> bool
	{
		set_impl!(self, al_set_sample_instance_gain, gain as c_float)
	}

	pub fn set_pan(&self, pan: Option<f32>) -> bool
	{
		set_impl!(self, al_set_sample_instance_pan,
		match pan
		{
			Some(p) => p as c_float,
			None => ALLEGRO_AUDIO_PAN_NONE
		})
	}

	pub fn set_speed(&self, speed: f32) -> bool
	{
		set_impl!(self, al_set_sample_instance_speed, speed as c_float)
	}

	pub fn set_playmode(&self, playmode: Playmode) -> bool
	{
		set_impl!(self, al_set_sample_instance_playmode, playmode.get())
	}

	pub fn get_frequency(&self) -> Option<u32>
	{
		get_opt_impl!(self, al_get_sample_instance_frequency, u32)
	}

	pub fn get_length(&self) -> Option<u32>
	{
		get_opt_impl!(self, al_get_sample_instance_length, u32)
	}

	pub fn get_position(&self) -> Option<u32>
	{
		get_opt_impl!(self, al_get_sample_instance_position, u32)
	}

	pub fn get_speed(&self) -> Option<f32>
	{
		get_opt_impl!(self, al_get_sample_instance_speed, f32)
	}

	pub fn get_gain(&self) -> Option<f32>
	{
		get_opt_impl!(self, al_get_sample_instance_gain, f32)
	}

	pub fn get_pan(&self) -> Option<f32>
	{
		get_opt_impl!(self, al_get_sample_instance_pan, f32)
	}

	pub fn get_time(&self) -> Option<f32>
	{
		get_opt_impl!(self, al_get_sample_instance_time, f32)
	}

	pub fn get_playmode(&self) -> Option<Playmode>
	{
		get_conv_impl!(self, al_get_sample_instance_playmode, Playmode::from_allegro)
	}

	pub fn get_channels(&self) -> Option<ChannelConf>
	{
		get_conv_impl!(self, al_get_sample_instance_channels, ChannelConf::from_allegro)
	}

	pub fn get_depth(&self) -> Option<AudioDepth>
	{
		get_conv_impl!(self, al_get_sample_instance_depth, AudioDepth::from_allegro)
	}

	pub fn get_playing(&self) -> bool
	{
		get_bool_impl!(self, al_get_sample_instance_playing)
	}

	pub fn get_attached(&self) -> bool
	{
		get_bool_impl!(self, al_get_sample_instance_attached)
	}

	pub fn get_allegro_sample_instance(&self) -> *mut ALLEGRO_SAMPLE_INSTANCE
	{
		self.allegro_sample_instance
	}
}

impl Drop for SampleInstance
{
	fn drop(&mut self)
	{
		self.detach();
		unsafe
		{
			al_destroy_sample_instance(self.allegro_sample_instance);
		}
	}
}

impl AttachToMixerImpl for SampleInstance
{
	fn create_connection(&mut self, allegro_mixer: *mut ALLEGRO_MIXER) -> Option<Connection>
	{
		if unsafe{ al_attach_sample_instance_to_mixer(self.allegro_sample_instance, allegro_mixer) == 0 }
		{
			None
		}
		else
		{
			let (c1, c2) = Connection::new(unsafe{ mem::transmute(self.allegro_sample_instance) }, SampleInstance::detach);
			self.parent = Some(c1);
			Some(c2)
		}
	}
}

impl AttachToMixer for SampleInstance
{
	fn detach(&mut self)
	{
		self.parent = None;
	}
}

impl ::addon::AudioAddon
{
	pub fn create_sample_instance(&self) -> Option<SampleInstance>
	{
		SampleInstance::new()
	}

	pub fn load_sample(&self, filename: &str) -> Option<Sample>
	{
		Sample::load(filename)
	}
}
<|endoftext|>


<commit_before>use game_map::{RoomId, GameMap};
use platform;
use command::{PrimaryCommand, CommandProcessor};

const PAUSE_MS: u64 = 1000;

#[derive(Debug, PartialEq, Copy, Clone)]
enum GameMode {
  AskName,
  Primary,
  Finished,
}

pub struct GameState<'a> {
  map: &'a mut GameMap<'a>,
  curr_mode: GameMode,
  player_name: String,
  curr_room: RoomId,
  show_desc: bool,
}

impl<'a> GameState<'a> {
  pub fn new(map: &'a mut GameMap<'a>) -> Self {
    Self {
      map: map,
      player_name: String::from(""),
      curr_mode: GameMode::AskName,
      curr_room: RoomId::Entrance,
      show_desc: true,
    }
  }

  pub fn is_finished(&self) -> bool {
    self.curr_mode == GameMode::Finished
  }

  pub fn tick_primary_mode(&mut self) {
    if self.show_desc {
      match self.curr_room {
        RoomId::Lift => {
          println!("You have entered the lift...");
          platform::sleep(PAUSE_MS);
          println!("It slowly descends...");
          platform::sleep(PAUSE_MS);
          self.curr_room = RoomId::RearVestibule;
          return;
        },
        RoomId::Exit => {
          println!("\nYou've done it!!");
          platform::sleep(PAUSE_MS);
          println!("That was the exit from the castle.");
          platform::sleep(PAUSE_MS);
          println!("\nYou have succeeded, {}!", self.player_name);
          println!("\nYou managed to get out of the castle.");
          platform::sleep(PAUSE_MS);
          println!("\nWell done!");
          platform::sleep(PAUSE_MS);
          self.curr_mode = GameMode::Finished;
          return;
        },
        _ => {
          println!("{}", self.map.room(self.curr_room).description);
        }
      }
      self.show_desc = false;
    }

    if let Some(cmd) = PrimaryCommand::get() {
      match cmd {
        PrimaryCommand::Go(dir) => {
          if let Some(room) = self.map.room(self.curr_room).get_exit(dir) {
            self.curr_room = room;
            self.show_desc = true;
          } else {
            println!("You can't go that way.");
          }
        },
        PrimaryCommand::Look => { self.show_desc = true; }
        PrimaryCommand::Quit => {
          if platform::is_browser() {
            println!("If you want to quit, close your browser.");
          } else {
            self.curr_mode = GameMode::Finished;
          }
        }
      }
    };
  }

  pub fn tick(&mut self) {
    match self.curr_mode {
      GameMode::AskName => {
        platform::show_prompt("What is your name, explorer? ");

        platform::read_input().map(|input| {
          if input.len() == 0 {
            println!("Pardon me?");
          } else {
            self.player_name = input;
            self.curr_mode = GameMode::Primary;
          }
        });
      },
      GameMode::Primary => { self.tick_primary_mode() },
      GameMode::Finished => {}
    }
  }
}
<commit_msg>Increase pause time to 3s.<commit_after>use game_map::{RoomId, GameMap};
use platform;
use command::{PrimaryCommand, CommandProcessor};

const PAUSE_MS: u64 = 3000;

#[derive(Debug, PartialEq, Copy, Clone)]
enum GameMode {
  AskName,
  Primary,
  Finished,
}

pub struct GameState<'a> {
  map: &'a mut GameMap<'a>,
  curr_mode: GameMode,
  player_name: String,
  curr_room: RoomId,
  show_desc: bool,
}

impl<'a> GameState<'a> {
  pub fn new(map: &'a mut GameMap<'a>) -> Self {
    Self {
      map: map,
      player_name: String::from(""),
      curr_mode: GameMode::AskName,
      curr_room: RoomId::Entrance,
      show_desc: true,
    }
  }

  pub fn is_finished(&self) -> bool {
    self.curr_mode == GameMode::Finished
  }

  pub fn tick_primary_mode(&mut self) {
    if self.show_desc {
      match self.curr_room {
        RoomId::Lift => {
          println!("You have entered the lift...");
          platform::sleep(PAUSE_MS);
          println!("It slowly descends...");
          platform::sleep(PAUSE_MS);
          self.curr_room = RoomId::RearVestibule;
          return;
        },
        RoomId::Exit => {
          println!("\nYou've done it!!");
          platform::sleep(PAUSE_MS);
          println!("That was the exit from the castle.");
          platform::sleep(PAUSE_MS);
          println!("\nYou have succeeded, {}!", self.player_name);
          println!("\nYou managed to get out of the castle.");
          platform::sleep(PAUSE_MS);
          println!("\nWell done!");
          platform::sleep(PAUSE_MS);
          self.curr_mode = GameMode::Finished;
          return;
        },
        _ => {
          println!("{}", self.map.room(self.curr_room).description);
        }
      }
      self.show_desc = false;
    }

    if let Some(cmd) = PrimaryCommand::get() {
      match cmd {
        PrimaryCommand::Go(dir) => {
          if let Some(room) = self.map.room(self.curr_room).get_exit(dir) {
            self.curr_room = room;
            self.show_desc = true;
          } else {
            println!("You can't go that way.");
          }
        },
        PrimaryCommand::Look => { self.show_desc = true; }
        PrimaryCommand::Quit => {
          if platform::is_browser() {
            println!("If you want to quit, close your browser.");
          } else {
            self.curr_mode = GameMode::Finished;
          }
        }
      }
    };
  }

  pub fn tick(&mut self) {
    match self.curr_mode {
      GameMode::AskName => {
        platform::show_prompt("What is your name, explorer? ");

        platform::read_input().map(|input| {
          if input.len() == 0 {
            println!("Pardon me?");
          } else {
            self.player_name = input;
            self.curr_mode = GameMode::Primary;
          }
        });
      },
      GameMode::Primary => { self.tick_primary_mode() },
      GameMode::Finished => {}
    }
  }
}
<|endoftext|>


<commit_before>/**********************************************************\
|                                                          |
|                          hprose                          |
|                                                          |
| Official WebSite: http://www.hprose.com/                 |
|                   http://www.hprose.org/                 |
|                                                          |
\**********************************************************/
/**********************************************************\
 *                                                        *
 * io/decoder.rs                                          *
 *                                                        *
 * hprose decoder for Rust.                               *
 *                                                        *
 * LastModified: Sep 21, 2016                             *
 * Author: Chen Fei <cf@hprose.com>                       *
 *                                                        *
\**********************************************************/

use std::hash::{Hash, BuildHasher};
use std::collections::HashMap;

pub trait Decoder {
    type Error;

    // Primitive types:
    fn read_nil(&mut self) -> Result<(), Self::Error>;
    fn read_bool(&mut self) -> Result<bool, Self::Error>;
    fn read_i64(&mut self) -> Result<i64, Self::Error>;
    fn read_u64(&mut self) -> Result<u64, Self::Error>;
    fn read_f32(&mut self) -> Result<f32, Self::Error>;
    fn read_f64(&mut self) -> Result<f64, Self::Error>;
    fn read_char(&mut self) -> Result<char, Self::Error>;
    fn read_string_without_tag(&mut self) -> Result<String, Self::Error>;
    fn read_string(&mut self) -> Result<String, Self::Error>;
    fn read_bytes(&mut self) -> Result<Vec<u8>, Self::Error>;

    // Compound types:

    // Specialized types:
    fn read_option<T, F>(&mut self, f: F) -> Result<T, Self::Error>
        where F: FnMut(&mut Self, bool) -> Result<T, Self::Error>;

    fn read_seq<T, F>(&mut self, f: F) -> Result<T, Self::Error>
        where F: FnOnce(&mut Self, usize) -> Result<T, Self::Error>;

    fn read_map<T, F>(&mut self, f: F) -> Result<T, Self::Error>
        where F: FnOnce(&mut Self, usize) -> Result<T, Self::Error>;

    // Reference:
}

pub trait Decodable: Sized {
    fn decode<D: Decoder>(d: &mut D) -> Result<Self, D::Error>;
}

impl Decodable for bool {
    fn decode<D: Decoder>(d: &mut D) -> Result<bool, D::Error> {
        d.read_bool()
    }
}

impl Decodable for i64 {
    fn decode<D: Decoder>(d: &mut D) -> Result<i64, D::Error> {
        d.read_i64()
    }
}

impl Decodable for u64 {
    fn decode<D: Decoder>(d: &mut D) -> Result<u64, D::Error> {
        d.read_u64()
    }
}

impl Decodable for f32 {
    fn decode<D: Decoder>(d: &mut D) -> Result<f32, D::Error> {
        d.read_f32()
    }
}

impl Decodable for f64 {
    fn decode<D: Decoder>(d: &mut D) -> Result<f64, D::Error> {
        d.read_f64()
    }
}

impl Decodable for char {
    fn decode<D: Decoder>(d: &mut D) -> Result<char, D::Error> {
        d.read_char()
    }
}

impl Decodable for String {
    fn decode<D: Decoder>(d: &mut D) -> Result<String, D::Error> {
        d.read_string()
    }
}

impl<T:Decodable> Decodable for Option<T> {
    fn decode<D: Decoder>(d: &mut D) -> Result<Option<T>, D::Error> {
        d.read_option(|d, b| {
            if b {
                Ok(Some(Decodable::decode(d)?))
            } else {
                Ok(None)
            }
        })
    }
}

impl<K, V, S> Decodable for HashMap<K, V, S>
where K: Decodable + Hash + Eq,
      V: Decodable,
      S: BuildHasher + Default
{
    fn decode<D: Decoder>(d: &mut D) -> Result<HashMap<K, V, S>, D::Error> {
        d.read_map(|d, len| {
            let state = Default::default();
            let mut map = HashMap::with_capacity_and_hasher(len, state);
            for i in 0..len {
                let key = Decodable::decode(d)?;
                let val = Decodable::decode(d)?;
                map.insert(key, val);
            }
            Ok(map)
        })
    }
}
<commit_msg>Added more pointer types & primitive types for decoder.<commit_after>/**********************************************************\
|                                                          |
|                          hprose                          |
|                                                          |
| Official WebSite: http://www.hprose.com/                 |
|                   http://www.hprose.org/                 |
|                                                          |
\**********************************************************/
/**********************************************************\
 *                                                        *
 * io/decoder.rs                                          *
 *                                                        *
 * hprose decoder for Rust.                               *
 *                                                        *
 * LastModified: Sep 22, 2016                             *
 * Author: Chen Fei <cf@hprose.com>                       *
 *                                                        *
\**********************************************************/

use std::rc::Rc;
use std::sync::Arc;
use std::borrow::Cow;
use std::marker::PhantomData;
use std::cell::{Cell, RefCell};
use std::hash::{Hash, BuildHasher};
use std::collections::HashMap;

pub trait Decoder {
    type Error;

    // Primitive types:
    fn read_nil(&mut self) -> Result<(), Self::Error>;
    fn read_bool(&mut self) -> Result<bool, Self::Error>;
    fn read_i64(&mut self) -> Result<i64, Self::Error>;
    fn read_u64(&mut self) -> Result<u64, Self::Error>;
    fn read_f32(&mut self) -> Result<f32, Self::Error>;
    fn read_f64(&mut self) -> Result<f64, Self::Error>;
    fn read_char(&mut self) -> Result<char, Self::Error>;
    fn read_string_without_tag(&mut self) -> Result<String, Self::Error>;
    fn read_string(&mut self) -> Result<String, Self::Error>;
    fn read_bytes(&mut self) -> Result<Vec<u8>, Self::Error>;

    // Compound types:

    // Specialized types:
    fn read_option<T, F>(&mut self, f: F) -> Result<T, Self::Error>
        where F: FnMut(&mut Self, bool) -> Result<T, Self::Error>;

    fn read_seq<T, F>(&mut self, f: F) -> Result<T, Self::Error>
        where F: FnOnce(&mut Self, usize) -> Result<T, Self::Error>;

    fn read_map<T, F>(&mut self, f: F) -> Result<T, Self::Error>
        where F: FnOnce(&mut Self, usize) -> Result<T, Self::Error>;

    // Reference:
}

pub trait Decodable: Sized {
    fn decode<D: Decoder>(d: &mut D) -> Result<Self, D::Error>;
}

impl Decodable for () {
    fn decode<D: Decoder>(d: &mut D) -> Result<(), D::Error> {
        d.read_nil()
    }
}

impl Decodable for bool {
    fn decode<D: Decoder>(d: &mut D) -> Result<bool, D::Error> {
        d.read_bool()
    }
}

impl Decodable for i8 {
    fn decode<D: Decoder>(d: &mut D) -> Result<i8, D::Error> {
        d.read_i64().map(|i| i as i8)
    }
}

impl Decodable for i16 {
    fn decode<D: Decoder>(d: &mut D) -> Result<i16, D::Error> {
        d.read_i64().map(|i| i as i16)
    }
}

impl Decodable for i32 {
    fn decode<D: Decoder>(d: &mut D) -> Result<i32, D::Error> {
        d.read_i64().map(|i| i as i32)
    }
}

impl Decodable for i64 {
    fn decode<D: Decoder>(d: &mut D) -> Result<i64, D::Error> {
        d.read_i64()
    }
}

impl Decodable for isize {
    fn decode<D: Decoder>(d: &mut D) -> Result<isize, D::Error> {
        d.read_i64().map(|i| i as isize)
    }
}

impl Decodable for u8 {
    fn decode<D: Decoder>(d: &mut D) -> Result<u8, D::Error> {
        d.read_u64().map(|u| u as u8)
    }
}

impl Decodable for u16 {
    fn decode<D: Decoder>(d: &mut D) -> Result<u16, D::Error> {
        d.read_u64().map(|u| u as u16)
    }
}

impl Decodable for u32 {
    fn decode<D: Decoder>(d: &mut D) -> Result<u32, D::Error> {
        d.read_u64().map(|u| u as u32)
    }
}

impl Decodable for u64 {
    fn decode<D: Decoder>(d: &mut D) -> Result<u64, D::Error> {
        d.read_u64()
    }
}

impl Decodable for usize {
    fn decode<D: Decoder>(d: &mut D) -> Result<usize, D::Error> {
        d.read_u64().map(|u| u as usize)
    }
}

impl Decodable for f32 {
    fn decode<D: Decoder>(d: &mut D) -> Result<f32, D::Error> {
        d.read_f32()
    }
}

impl Decodable for f64 {
    fn decode<D: Decoder>(d: &mut D) -> Result<f64, D::Error> {
        d.read_f64()
    }
}

impl Decodable for char {
    fn decode<D: Decoder>(d: &mut D) -> Result<char, D::Error> {
        d.read_char()
    }
}

impl Decodable for String {
    fn decode<D: Decoder>(d: &mut D) -> Result<String, D::Error> {
        d.read_string()
    }
}

impl<T: Decodable> Decodable for Box<T> {
    fn decode<D: Decoder>(d: &mut D) -> Result<Box<T>, D::Error> {
        Ok(Box::new(try!(Decodable::decode(d))))
    }
}

impl<T: Decodable> Decodable for Rc<T> {
    #[inline]
    fn decode<D: Decoder>(d: &mut D) -> Result<Rc<T>, D::Error> {
        Ok(Rc::new(try!(Decodable::decode(d))))
    }
}

impl<T: Decodable + Send + Sync> Decodable for Arc<T> {
    fn decode<D: Decoder>(d: &mut D) -> Result<Arc<T>, D::Error> {
        Ok(Arc::new(try!(Decodable::decode(d))))
    }
}

impl<'a, T: ?Sized> Decodable for Cow<'a, T>
where T: ToOwned, T::Owned: Decodable
{
    #[inline]
    fn decode<D: Decoder>(d: &mut D) -> Result<Cow<'static, T>, D::Error> {
        Ok(Cow::Owned(try!(Decodable::decode(d))))
    }
}

impl<T: Decodable + Copy> Decodable for Cell<T> {
    fn decode<D: Decoder>(d: &mut D) -> Result<Cell<T>, D::Error> {
        Ok(Cell::new(try!(Decodable::decode(d))))
    }
}

impl<T: Decodable> Decodable for RefCell<T> {
    fn decode<D: Decoder>(d: &mut D) -> Result<RefCell<T>, D::Error> {
        Ok(RefCell::new(try!(Decodable::decode(d))))
    }
}

impl<K, V, S> Decodable for HashMap<K, V, S>
where K: Decodable + Hash + Eq,
      V: Decodable,
      S: BuildHasher + Default
{
    fn decode<D: Decoder>(d: &mut D) -> Result<HashMap<K, V, S>, D::Error> {
        d.read_map(|d, len| {
            let state = Default::default();
            let mut map = HashMap::with_capacity_and_hasher(len, state);
            for i in 0..len {
                let key = Decodable::decode(d)?;
                let val = Decodable::decode(d)?;
                map.insert(key, val);
            }
            Ok(map)
        })
    }
}

impl<T: Decodable> Decodable for Option<T> {
    fn decode<D: Decoder>(d: &mut D) -> Result<Option<T>, D::Error> {
        d.read_option(|d, b| {
            if b {
                Ok(Some(Decodable::decode(d)?))
            } else {
                Ok(None)
            }
        })
    }
}

impl<T> Decodable for PhantomData<T> {
    fn decode<D: Decoder>(d: &mut D) -> Result<PhantomData<T>, D::Error> {
        d.read_nil().and(Ok(PhantomData))
    }
}
<|endoftext|>


<commit_before>use ffi;

use Void;
use Is;
use CefRc;
use unsafe_downcast_mut;
use std::mem::zeroed;
use std::ops::{Deref, DerefMut};

trait ResourceBundleHandler {}
impl ResourceBundleHandler for Void {}
trait BrowserProcessHandler {}
impl BrowserProcessHandler for Void {}
trait RenderProcessHandler {}
impl RenderProcessHandler for Void {}

#[allow(unused_variables)]
pub trait App : 'static {
    type OutResourceBundleHandler : ResourceBundleHandler = Void;
    type OutBrowserProcessHandler : BrowserProcessHandler = Void;
    type OutRenderProcessHandler : RenderProcessHandler = Void;

    fn on_before_command_line_processing(&mut self,
                                         process_type: &ffi::cef_string_t,
                                         command_line: &mut ffi::cef_command_line_t) {}
    fn on_register_custom_schemes(&mut self, registrar: &mut ffi::cef_scheme_registrar_t) {}
    fn get_resource_bundle_handler(&mut self) -> Option<Self::OutResourceBundleHandler> { None }
    fn get_browser_process_handler(&mut self) -> Option<Self::OutBrowserProcessHandler> { None }
    fn get_render_process_handler(&mut self) -> Option<Self::OutRenderProcessHandler> { None }
}

impl App for Void {
    type OutResourceBundleHandler = Void;
    type OutBrowserProcessHandler = Void;
    type OutRenderProcessHandler = Void;
}

#[repr(C)]
pub struct AppWrapper<T : App> {
    vtable: ffi::cef_app_t,
    callback: T
}

impl<T : App> Deref for AppWrapper<T> {
    type Target = T;
    fn deref<'a>(&'a self) -> &'a T {
        &self.callback
    }
}

impl<T : App> DerefMut for AppWrapper<T> {
    fn deref_mut<'a>(&'a mut self) -> &'a mut T {
        &mut self.callback
    }
}

unsafe impl<T: App> Is<ffi::cef_base_t> for AppWrapper<T> {}
unsafe impl<T: App> Is<ffi::cef_app_t> for AppWrapper<T> {}

impl<T : App> AppWrapper<T> {
    pub fn new(wrapped: T) -> CefRc<AppWrapper<T>> {
        #[stdcall_win]
        extern fn obclp<T : App>(_self: *mut ffi::cef_app_t,
                        process_type: *const ffi::cef_string_t,
                        command_line: *mut ffi::cef_command_line_t) {
            unsafe {
                let this : &mut AppWrapper<T> = unsafe_downcast_mut(&mut *_self);
                this.callback.on_before_command_line_processing(&*process_type, &mut *command_line);
            }
        }
        #[stdcall_win]
        extern fn orcs<T : App>(_self: *mut ffi::cef_app_t,
                                     registrar: *mut ffi::cef_scheme_registrar_t) {
            unsafe {
                let this : &mut AppWrapper<T> = unsafe_downcast_mut(&mut *_self);
                this.callback.on_register_custom_schemes(&mut *registrar);
            }
        }
        #[stdcall_win]
        extern fn grbh<T : App>(_self: *mut ffi::cef_app_t) -> *mut ffi::cef_resource_bundle_handler_t {
            unsafe {
                zeroed()
                //let this : &mut App<T> = unsafe_downcast_mut(&mut *_self);
                //this.callback.get_resource_bundle_handler().map(|x| upcast_ptr(x)).unwrap_or_else(|| zeroed())
            }
        }
        #[stdcall_win]
        extern fn gbph<T : App>(_self: *mut ffi::cef_app_t) -> *mut ffi::cef_browser_process_handler_t {
            unsafe {
                zeroed()
                //let this : &mut App<T> = transmute_mut_ref(&mut *_self);
                //this.callback.get_browser_process_handler().map(|x| transmute(x)).unwrap_or_else(|| zeroed())
            }
        }
        #[stdcall_win]
        extern fn grph<T : App>(_self: *mut ffi::cef_app_t) -> *mut ffi::cef_render_process_handler_t {
            unsafe {
                zeroed()
                //let this : &mut App<T> = transmute_mut_ref(&mut *_self);
                //this.callback.get_render_process_handler().map(|x| transmute(x)).unwrap_or_else(|| zeroed())
            }
        }
        CefRc::make(move |base| {
            AppWrapper {
                vtable: ffi::cef_app_t {
                    base: base,
                    on_before_command_line_processing: Some(obclp::<T>),
                    on_register_custom_schemes: Some(orcs::<T>),
                    get_resource_bundle_handler: Some(grbh::<T>),
                    get_browser_process_handler: Some(gbph::<T>),
                    get_render_process_handler: Some(grph::<T>)
                },
                callback: wrapped
            }
        })
    }
}
<commit_msg>Removed unnecessary braces.<commit_after>use ffi;

use Void;
use Is;
use CefRc;
use unsafe_downcast_mut;
use std::mem::zeroed;
use std::ops::{Deref, DerefMut};

trait ResourceBundleHandler {}
impl ResourceBundleHandler for Void {}
trait BrowserProcessHandler {}
impl BrowserProcessHandler for Void {}
trait RenderProcessHandler {}
impl RenderProcessHandler for Void {}

#[allow(unused_variables)]
pub trait App : 'static {
    type OutResourceBundleHandler : ResourceBundleHandler = Void;
    type OutBrowserProcessHandler : BrowserProcessHandler = Void;
    type OutRenderProcessHandler : RenderProcessHandler = Void;

    fn on_before_command_line_processing(&mut self,
                                         process_type: &ffi::cef_string_t,
                                         command_line: &mut ffi::cef_command_line_t) {}
    fn on_register_custom_schemes(&mut self, registrar: &mut ffi::cef_scheme_registrar_t) {}
    fn get_resource_bundle_handler(&mut self) -> Option<Self::OutResourceBundleHandler> { None }
    fn get_browser_process_handler(&mut self) -> Option<Self::OutBrowserProcessHandler> { None }
    fn get_render_process_handler(&mut self) -> Option<Self::OutRenderProcessHandler> { None }
}

impl App for Void {
    type OutResourceBundleHandler = Void;
    type OutBrowserProcessHandler = Void;
    type OutRenderProcessHandler = Void;
}

#[repr(C)]
pub struct AppWrapper<T : App> {
    vtable: ffi::cef_app_t,
    callback: T
}

impl<T : App> Deref for AppWrapper<T> {
    type Target = T;
    fn deref<'a>(&'a self) -> &'a T {
        &self.callback
    }
}

impl<T : App> DerefMut for AppWrapper<T> {
    fn deref_mut<'a>(&'a mut self) -> &'a mut T {
        &mut self.callback
    }
}

unsafe impl<T: App> Is<ffi::cef_base_t> for AppWrapper<T> {}
unsafe impl<T: App> Is<ffi::cef_app_t> for AppWrapper<T> {}

impl<T : App> AppWrapper<T> {
    pub fn new(wrapped: T) -> CefRc<AppWrapper<T>> {
        #[stdcall_win]
        extern fn obclp<T : App>(_self: *mut ffi::cef_app_t,
                        process_type: *const ffi::cef_string_t,
                        command_line: *mut ffi::cef_command_line_t) {
            unsafe {
                let this : &mut AppWrapper<T> = unsafe_downcast_mut(&mut *_self);
                this.callback.on_before_command_line_processing(&*process_type, &mut *command_line);
            }
        }
        #[stdcall_win]
        extern fn orcs<T : App>(_self: *mut ffi::cef_app_t,
                                     registrar: *mut ffi::cef_scheme_registrar_t) {
            unsafe {
                let this : &mut AppWrapper<T> = unsafe_downcast_mut(&mut *_self);
                this.callback.on_register_custom_schemes(&mut *registrar);
            }
        }
        #[stdcall_win]
        extern fn grbh<T : App>(_self: *mut ffi::cef_app_t) -> *mut ffi::cef_resource_bundle_handler_t {
            unsafe {
                zeroed()
                //let this : &mut App<T> = unsafe_downcast_mut(&mut *_self);
                //this.callback.get_resource_bundle_handler().map(|x| upcast_ptr(x)).unwrap_or_else(|| zeroed())
            }
        }
        #[stdcall_win]
        extern fn gbph<T : App>(_self: *mut ffi::cef_app_t) -> *mut ffi::cef_browser_process_handler_t {
            unsafe {
                zeroed()
                //let this : &mut App<T> = transmute_mut_ref(&mut *_self);
                //this.callback.get_browser_process_handler().map(|x| transmute(x)).unwrap_or_else(|| zeroed())
            }
        }
        #[stdcall_win]
        extern fn grph<T : App>(_self: *mut ffi::cef_app_t) -> *mut ffi::cef_render_process_handler_t {
            unsafe {
                zeroed()
                //let this : &mut App<T> = transmute_mut_ref(&mut *_self);
                //this.callback.get_render_process_handler().map(|x| transmute(x)).unwrap_or_else(|| zeroed())
            }
        }
        CefRc::make(move |base| AppWrapper {
            vtable: ffi::cef_app_t {
                base: base,
                on_before_command_line_processing: Some(obclp::<T>),
                on_register_custom_schemes: Some(orcs::<T>),
                get_resource_bundle_handler: Some(grbh::<T>),
                get_browser_process_handler: Some(gbph::<T>),
                get_render_process_handler: Some(grph::<T>)
            },
            callback: wrapped
        })
    }
}
<|endoftext|>


<commit_before>use reqwest::Client;
use serde_json;
use serde_json::Value;

use error::{Result, check_for_error};
use error::Error::{RequestFailed, JsonNotFound};
use objects::update::Update;
use objects::message::Message;
use value_extension::ValueExtension;

/// A struct which contains things associated with the bot.
#[derive(Debug)]
pub struct Bot {
    pub id: i64,
    pub first_name: String,
    pub last_name: Option<String>,
    pub username: String,
    client: Client,
    pub bot_url: String,
}

pub enum ParseMode {
    Markdown,
    Html,
    Text,
}

impl Bot {
    /// Return a new bot struct.
    pub fn new(bot_url: String) -> Result<Self> {
        let client = Client::new()?;
        let rjson = Bot::get_me(&client, &bot_url)?;
        let id = rjson.as_required_i64("id")?;
        let first_name = rjson.as_required_string("first_name")?;
        let last_name = rjson.as_optional_string("last_name");
        let username = rjson.as_required_string("username")?;

        Ok(Bot {
            id: id,
            first_name: first_name,
            last_name: last_name,
            username: username,
            client: client,
            bot_url: bot_url,
        })
    }

    /// Gets the information about the bot.
    fn get_me(client: &Client, bot_url: &str) -> Result<Value> {
        let path = ["getMe"];
        let url = ::construct_api_url(bot_url, &path);
        let mut resp = client.get(&url).send()?;

        if resp.status().is_success() {
            let rjson: Value = resp.json()?;
            rjson.find("result").cloned().ok_or(JsonNotFound)
        } else {
            Err(RequestFailed(*resp.status()))
        }
    }

    fn get_parse_mode(&self, parse_mode: &ParseMode) -> String {
        match parse_mode {
                &ParseMode::Text => "None",
                &ParseMode::Markdown => "Markdown",
                &ParseMode::Html => "HTML",
            }
            .to_string()
    }

    pub fn get_updates(&self,
                       offset: i32,
                       limit: Option<i32>,
                       timeout: Option<i32>,
                       network_delay: Option<i32>)
                       -> Result<Option<Vec<Update>>> {
        let limit = limit.unwrap_or(100);
        let timeout = timeout.unwrap_or(0);
        // Use network_delay when it gets implemented
        let network_delay = network_delay.unwrap_or(5);
        let path = ["getUpdates"];
        let path_url = ::construct_api_url(&self.bot_url, &path);
        let url = format!("{}?offset={}&limit={}&timeout={}",
                          path_url,
                          offset,
                          limit,
                          timeout);
        let mut data = self.client.get(&url).send()?;
        let rjson: Value = check_for_error(data.json()?)?;
        let updates_json = rjson.find("result");

        if let Some(result) = updates_json {
            let updates: Vec<Update> = serde_json::from_value(result.clone())?;
            Ok(Some(updates))
        } else {
            Ok(None)
        }
    }

    pub fn send_message(&self,
                        chat_id: &i64,
                        text: &str,
                        parse_mode: Option<&ParseMode>,
                        disable_web_page_preview: Option<&bool>,
                        disable_notification: Option<&bool>,
                        reply_to_message_id: Option<&i32>)
                        -> Result<Message> {
        let chat_id: &str = &chat_id.to_string();
        let parse_mode = &self.get_parse_mode(parse_mode.unwrap_or(&ParseMode::Text));
        let disable_web_page_preview: &str = &disable_web_page_preview.unwrap_or(&false)
            .to_string();
        let disable_notification: &str = &disable_notification.unwrap_or(&false).to_string();
        let reply_to_message_id: &str = &reply_to_message_id.map(|i| i.to_string())
            .unwrap_or("None".to_string());
        let path = ["sendMessage"];
        let url = ::construct_api_url(&self.bot_url, &path);
        let params = [("chat_id", chat_id),
                      ("text", text),
                      ("parse_mode", parse_mode),
                      ("disable_web_page_preview", disable_web_page_preview),
                      ("disable_notification", disable_notification),
                      ("reply_to_message_id", reply_to_message_id)];
        let mut data = self.client.post(&url).form(&params).send()?;
        let rjson: Value = check_for_error(data.json()?)?;
        let message_json = rjson.find("result").ok_or(JsonNotFound)?;
        let message: Message = serde_json::from_value(message_json.clone())?;
        Ok(message)
    }

    pub fn reply_to_message(&self, update: &Update, text: &str) -> Result<Message> {
        let chat_id = update.clone().message.unwrap().chat.id;
        self.send_message(&chat_id, text, None, None, None, None)
    }
}
<commit_msg>Making get_me public<commit_after>use reqwest::Client;
use serde_json;
use serde_json::Value;

use error::{Result, check_for_error};
use error::Error::{RequestFailed, JsonNotFound};
use objects::update::Update;
use objects::message::Message;
use value_extension::ValueExtension;

/// A struct which contains things associated with the bot.
#[derive(Debug)]
pub struct Bot {
    pub id: i64,
    pub first_name: String,
    pub last_name: Option<String>,
    pub username: String,
    client: Client,
    pub bot_url: String,
}

pub enum ParseMode {
    Markdown,
    Html,
    Text,
}

impl Bot {
    /// Return a new bot struct.
    pub fn new(bot_url: String) -> Result<Self> {
        let client = Client::new()?;
        let rjson = Bot::get_me(&client, &bot_url)?;
        let id = rjson.as_required_i64("id")?;
        let first_name = rjson.as_required_string("first_name")?;
        let last_name = rjson.as_optional_string("last_name");
        let username = rjson.as_required_string("username")?;

        Ok(Bot {
            id: id,
            first_name: first_name,
            last_name: last_name,
            username: username,
            client: client,
            bot_url: bot_url,
        })
    }

    /// Gets the information about the bot.
    pub fn get_me(client: &Client, bot_url: &str) -> Result<Value> {
        let path = ["getMe"];
        let url = ::construct_api_url(bot_url, &path);
        let mut resp = client.get(&url).send()?;

        if resp.status().is_success() {
            let rjson: Value = resp.json()?;
            rjson.find("result").cloned().ok_or(JsonNotFound)
        } else {
            Err(RequestFailed(*resp.status()))
        }
    }

    pub fn get_updates(&self,
                       offset: i32,
                       limit: Option<i32>,
                       timeout: Option<i32>,
                       network_delay: Option<i32>)
                       -> Result<Option<Vec<Update>>> {
        let limit = limit.unwrap_or(100);
        let timeout = timeout.unwrap_or(0);
        // Use network_delay when it gets implemented
        let network_delay = network_delay.unwrap_or(5);
        let path = ["getUpdates"];
        let path_url = ::construct_api_url(&self.bot_url, &path);
        let url = format!("{}?offset={}&limit={}&timeout={}",
                          path_url,
                          offset,
                          limit,
                          timeout);
        let mut data = self.client.get(&url).send()?;
        let rjson: Value = check_for_error(data.json()?)?;
        let updates_json = rjson.find("result");

        if let Some(result) = updates_json {
            let updates: Vec<Update> = serde_json::from_value(result.clone())?;
            Ok(Some(updates))
        } else {
            Ok(None)
        }
    }

    pub fn send_message(&self,
                        chat_id: &i64,
                        text: &str,
                        parse_mode: Option<&ParseMode>,
                        disable_web_page_preview: Option<&bool>,
                        disable_notification: Option<&bool>,
                        reply_to_message_id: Option<&i32>)
                        -> Result<Message> {
        let chat_id: &str = &chat_id.to_string();
        let parse_mode = &self.get_parse_mode(parse_mode.unwrap_or(&ParseMode::Text));
        let disable_web_page_preview: &str = &disable_web_page_preview.unwrap_or(&false)
            .to_string();
        let disable_notification: &str = &disable_notification.unwrap_or(&false).to_string();
        let reply_to_message_id: &str = &reply_to_message_id.map(|i| i.to_string())
            .unwrap_or("None".to_string());
        let path = ["sendMessage"];
        let url = ::construct_api_url(&self.bot_url, &path);
        let params = [("chat_id", chat_id),
                      ("text", text),
                      ("parse_mode", parse_mode),
                      ("disable_web_page_preview", disable_web_page_preview),
                      ("disable_notification", disable_notification),
                      ("reply_to_message_id", reply_to_message_id)];
        let mut data = self.client.post(&url).form(&params).send()?;
        let rjson: Value = check_for_error(data.json()?)?;
        let message_json = rjson.find("result").ok_or(JsonNotFound)?;
        let message: Message = serde_json::from_value(message_json.clone())?;
        Ok(message)
    }

    pub fn reply_to_message(&self, update: &Update, text: &str) -> Result<Message> {
        let chat_id = update.clone().message.unwrap().chat.id;
        self.send_message(&chat_id, text, None, None, None, None)
    }

    fn get_parse_mode(&self, parse_mode: &ParseMode) -> String {
        match parse_mode {
                &ParseMode::Text => "None",
                &ParseMode::Markdown => "Markdown",
                &ParseMode::Html => "HTML",
            }
            .to_string()
    }
}
<|endoftext|>


<commit_before>use getopts;

pub const USAGE: &'static str = "Usage: corectl [OPTIONS] COMMAND [COMMAND OPTIONS]

Commands:
    deploy      Deploy fleet units
    help        Output this help message
    version     Output corectl's version number";

pub fn run(args: Vec<String>) -> Result<String, String> {
    let mut options = getopts::Options::new();
    options.optflag("h", "help", "Output this help message");
    options.optflag("v", "version", "Output corectl's version number");
    let matches = match options.parse(args.iter().skip(1)) {
        Ok(matches) => matches,
        Err(fail) => return Err(fail.to_err_msg())
    };
    let usage = Ok(options.usage(USAGE));

    if matches.opt_present("v") {
        return version();
    } else if matches.opt_present("h") {
        return usage;
    }

    if matches.free.len() == 0 {
        return usage;
    }

    let command = matches.free[0].as_slice();

    match command {
        "version" => version(),
        "deploy" => deploy(matches.free.clone()),
        "help" => usage,
        unknown => { Err(format!("Unknown command: {}. Run `corectl` for help.", unknown)) }
    }
}

fn deploy(args: Vec<String>) -> Result<String, String> {
    Ok("Deployed stuff.".to_string())
}

fn version() -> Result<String, String> {
    Ok(env!("CARGO_PKG_VERSION").to_string())
}

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

    #[test]
    fn it_prints_help_with_no_args() {
        let output = run(vec!["corectl".to_string()]);

        assert!(output.unwrap().starts_with(USAGE));
    }

    #[test]
    fn it_prints_help_with_help_command() {
        let output = run(vec!["corectl".to_string(), "help".to_string()]);

        assert!(output.unwrap().starts_with(USAGE));
    }

    #[test]
    fn it_prints_help_with_help_flag() {
        let output = run(vec!["corectl".to_string(), "--help".to_string()]);

        assert!(output.unwrap().starts_with(USAGE));
    }

    #[test]
    fn it_prints_help_with_h_flag() {
        let output = run(vec!["corectl".to_string(), "-h".to_string()]);

        assert!(output.unwrap().starts_with(USAGE));
    }

    #[test]
    fn it_prints_version_with_version_command() {
        let output = run(vec!["corectl".to_string(), "version".to_string()]);

        assert_eq!(output.unwrap(), env!("CARGO_PKG_VERSION"));
    }

    #[test]
    fn it_prints_version_with_version_flag() {
        let output = run(vec!["corectl".to_string(), "--version".to_string()]);

        assert_eq!(output.unwrap(), env!("CARGO_PKG_VERSION"));
    }

    #[test]
    fn it_prints_version_with_v_flag() {
        let output = run(vec!["corectl".to_string(), "-v".to_string()]);

        assert_eq!(output.unwrap(), env!("CARGO_PKG_VERSION"));
    }
}
<commit_msg>Add service command stub and improve help message.<commit_after>use getopts;

pub const USAGE: &'static str = "\
Usage: corectl [OPTIONS] COMMAND [COMMAND OPTIONS]
       corectl help COMMAND

Commands:
    deploy      Deploy a new version of a service
    service     Create or delete services
    help        Output this help message, or help for COMMAND
    version     Output corectl's version number\
";

pub fn run(args: Vec<String>) -> Result<String, String> {
    let mut options = getopts::Options::new();
    options.optflag("h", "help", "Output this help message");
    options.optflag("v", "version", "Output corectl's version number");
    let matches = match options.parse(args.iter().skip(1)) {
        Ok(matches) => matches,
        Err(fail) => return Err(fail.to_err_msg())
    };
    let usage = Ok(options.usage(USAGE));

    if matches.opt_present("v") {
        return version();
    } else if matches.opt_present("h") {
        return usage;
    }

    if matches.free.len() == 0 {
        return usage;
    }

    let command = matches.free[0].as_slice();

    match command {
        "version" => version(),
        "deploy" => deploy(matches.free.clone()),
        "service" => service(matches.free.clone()),
        "help" => usage,
        unknown => { Err(format!("Unknown command: {}. Run `corectl` for help.", unknown)) }
    }
}

fn deploy(args: Vec<String>) -> Result<String, String> {
    Ok("Deployed stuff.".to_string())
}

fn service(args: Vec<String>) -> Result<String, String> {
    Ok("Added/removed service.".to_string())
}

fn version() -> Result<String, String> {
    Ok(env!("CARGO_PKG_VERSION").to_string())
}

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

    #[test]
    fn it_prints_help_with_no_args() {
        let output = run(vec!["corectl".to_string()]);

        assert!(output.unwrap().starts_with(USAGE));
    }

    #[test]
    fn it_prints_help_with_help_command() {
        let output = run(vec!["corectl".to_string(), "help".to_string()]);

        assert!(output.unwrap().starts_with(USAGE));
    }

    #[test]
    fn it_prints_help_with_help_flag() {
        let output = run(vec!["corectl".to_string(), "--help".to_string()]);

        assert!(output.unwrap().starts_with(USAGE));
    }

    #[test]
    fn it_prints_help_with_h_flag() {
        let output = run(vec!["corectl".to_string(), "-h".to_string()]);

        assert!(output.unwrap().starts_with(USAGE));
    }

    #[test]
    fn it_prints_version_with_version_command() {
        let output = run(vec!["corectl".to_string(), "version".to_string()]);

        assert_eq!(output.unwrap(), env!("CARGO_PKG_VERSION"));
    }

    #[test]
    fn it_prints_version_with_version_flag() {
        let output = run(vec!["corectl".to_string(), "--version".to_string()]);

        assert_eq!(output.unwrap(), env!("CARGO_PKG_VERSION"));
    }

    #[test]
    fn it_prints_version_with_v_flag() {
        let output = run(vec!["corectl".to_string(), "-v".to_string()]);

        assert_eq!(output.unwrap(), env!("CARGO_PKG_VERSION"));
    }
}
<|endoftext|>