<commit_before>extern crate rmp_serde;
extern crate time;

use std::cmp;
use std::collections::HashMap;
use std::ops::Add;

use commands::{Command, CommandExecutor};
use commands::pool::PoolCommand;
use errors::common::CommonError;
use errors::pool::PoolError;
use self::time::Duration;
use super::{
    MerkleTree,
    RemoteNode,
};
use super::rust_base58::{FromBase58, ToBase58};
use super::types::*;

pub const CATCHUP_ROUND_TIMEOUT: i64 = 50;

enum CatchupStepResult {
    Finished,
    Continue,
    FailedAtNode(usize),
}

enum CatchupProgress {
    ShouldBeStarted,
    NotNeeded,
    Finished(MerkleTree),
    InProgress,
}

pub struct CatchupHandler {
    pub f: usize,
    pub ledger_status_same: usize,
    pub merkle_tree: MerkleTree,
    pub target_mt_size: usize,
    pub target_mt_root: Vec<u8>,
    pub new_mt_vote: usize,
    pub nodes: Vec<RemoteNode>,
    pub initiate_cmd_id: i32,
    pub is_refresh: bool,
    pub pending_catchup: Option<CatchUpProcess>,
    pub timeout: time::Tm,
    pub pool_id: i32,
    pub nodes_votes: Vec<Option<(String, usize)>>,
}

impl Default for CatchupHandler {
    fn default() -> Self {
        CatchupHandler {
            f: 0,
            ledger_status_same: 0,
            merkle_tree: MerkleTree::from_vec(Vec::new()).unwrap(),
            nodes: Vec::new(),
            target_mt_size: 0,
            new_mt_vote: 0,
            target_mt_root: Vec::new(),
            pending_catchup: None,
            initiate_cmd_id: 0,
            is_refresh: false,
            pool_id: 0,
            nodes_votes: Vec::new(),
            timeout: time::now_utc(),
        }
    }
}

impl CatchupHandler {
    pub fn process_msg(&mut self, msg: Message, raw_msg: &String, src_ind: usize) -> Result<Option<MerkleTree>, PoolError> {
        let catchup_status: CatchupProgress = match msg {
            Message::Pong => {
                //sending ledger status
                //TODO not send ledger status directly as response on ping, wait pongs from all nodes?
                let ls: LedgerStatus = LedgerStatus {
                    txnSeqNo: self.nodes.len(),
                    merkleRoot: self.merkle_tree.root_hash().as_slice().to_base58(),
                    ledgerId: 0,
                    ppSeqNo: None,
                    viewNo: None,
                };
                let resp_msg: Message = Message::LedgerStatus(ls);
                self.nodes[src_ind].send_msg(&resp_msg)?;
                CatchupProgress::InProgress
            }
            Message::LedgerStatus(ledger_status) => {
                self.nodes_votes[src_ind] = Some((ledger_status.merkleRoot, ledger_status.txnSeqNo));
                self.check_nodes_responses_on_status()?
            }
            Message::ConsistencyProof(cons_proof) => {
                self.nodes_votes[src_ind] = Some((cons_proof.newMerkleRoot, cons_proof.seqNoEnd));
                self.check_nodes_responses_on_status()?
            }
            Message::CatchupRep(catchup) => {
                self.process_catchup_rep(catchup, src_ind)?
            }
            _ => {
                warn!("unhandled msg {:?}", msg);
                CatchupProgress::InProgress
            }
        };

        match catchup_status {
            CatchupProgress::Finished(mt) => return Ok(Some(mt)),
            CatchupProgress::NotNeeded => return Ok(Some(self.merkle_tree.clone())),
            CatchupProgress::ShouldBeStarted => self.start_catchup()?,
            CatchupProgress::InProgress => { /* nothing to do */ }
        }
        Ok(None)
    }

    fn check_nodes_responses_on_status(&mut self) -> Result<CatchupProgress, PoolError> {
        if self.pending_catchup.is_some() {
            return Ok(CatchupProgress::InProgress);
        }
        let mut votes: HashMap<(String, usize), usize> = HashMap::new();
        for node_vote in &self.nodes_votes {
            if let &Some(ref node_vote) = node_vote {
                let cnt = *votes.get(&node_vote).unwrap_or(&0) + 1;
                votes.insert((node_vote.0.clone(), node_vote.1), cnt);
            }
        }
        if let Some((most_popular_vote, votes_cnt)) = votes.iter().max_by_key(|entry| entry.1) {
            if *votes_cnt == self.nodes.len() - self.f {
                let &(ref target_mt_root, target_mt_size) = most_popular_vote;
                let cur_mt_size = self.merkle_tree.count();
                let cur_mt_hash = self.merkle_tree.root_hash().to_base58();
                if target_mt_size == cur_mt_size {
                    if cur_mt_hash.eq(target_mt_root) {
                        return Ok(CatchupProgress::NotNeeded);
                    } else {
                        return Err(PoolError::CommonError(CommonError::InvalidState(
                            "Ledger merkle tree doesn't acceptable for current tree.".to_string())));
                    }
                } else if target_mt_size > cur_mt_size {
                    self.target_mt_size = target_mt_size;
                    self.target_mt_root = target_mt_root.from_base58().map_err(|_|
                        CommonError::InvalidStructure(
                            "Can't parse target MerkleTree hash from nodes responses".to_string()))?;
                    return Ok(CatchupProgress::ShouldBeStarted);
                } else {
                    return Err(PoolError::CommonError(CommonError::InvalidState(
                        "Local merkle tree greater than mt from ledger".to_string())));
                }
            }
        }
        Ok(CatchupProgress::InProgress)
    }

    pub fn reset_nodes_votes(&mut self) {
        self.nodes_votes.clear();
        self.nodes_votes.resize(self.nodes.len(), None);
    }

    pub fn start_catchup(&mut self) -> Result<(), PoolError> {
        trace!("start_catchup");
        if self.pending_catchup.is_some() {
            return Err(PoolError::CommonError(
                CommonError::InvalidState(
                    "CatchUp already started for the pool".to_string())));
        }
        if self.merkle_tree.count() != self.nodes.len() {
            return Err(PoolError::CommonError(
                CommonError::InvalidState(
                    "Merkle tree doesn't equal nodes count".to_string())));
        }

        let node_cnt = self.nodes.iter().filter(|node| !node.is_blacklisted).count();
        let cnt_to_catchup = self.target_mt_size - self.merkle_tree.count();
        if cnt_to_catchup <= 0 {
            return Err(PoolError::CommonError(CommonError::InvalidState(
                "Nothing to CatchUp, but started".to_string())));
        }

        self.pending_catchup = Some(CatchUpProcess {
            merkle_tree: self.merkle_tree.clone(),
            pending_reps: Vec::new(),
            resp_not_received_node_idx: (0..self.nodes.len()).collect(),
        });
        self.timeout = time::now_utc().add(Duration::seconds(CATCHUP_ROUND_TIMEOUT));

        let portion = (cnt_to_catchup + node_cnt - 1) / node_cnt; //TODO check standard round up div
        let mut catchup_req = CatchupReq {
            ledgerId: 0,
            seqNoStart: node_cnt + 1,
            seqNoEnd: node_cnt + 1 + portion - 1,
            catchupTill: self.target_mt_size,
        };
        for node in &self.nodes {
            //TODO do not perform duplicate requests, update resp_not_received_node_idx
            if node.is_blacklisted {
                continue;
            }
            node.send_msg(&Message::CatchupReq(catchup_req.clone()))?;
            catchup_req.seqNoStart += portion;
            catchup_req.seqNoEnd = cmp::min(catchup_req.seqNoStart + portion - 1,
                                            catchup_req.catchupTill);
        }
        Ok(())
    }

    fn process_catchup_rep(&mut self, catchup: CatchupRep, node_idx: usize) -> Result<CatchupProgress, PoolError> {
        trace!("append {:?}", catchup);
        let catchup_finished = self.catchup_step(catchup, node_idx)?;
        match catchup_finished {
            CatchupStepResult::Finished => return Ok(CatchupProgress::Finished(self.finish_catchup()?)),
            CatchupStepResult::Continue => { /* nothing to do */ }
            CatchupStepResult::FailedAtNode(failed_node_idx) => {
                warn!("Fail to continue catch-up by response from node with idx {}. Node will be blacklisted and catchup will be restarted", failed_node_idx);
                self.nodes[failed_node_idx].is_blacklisted = true;
                self.pending_catchup = None;
                // TODO may be send ledger status again and re-obtain target MerkleTree params
                self.start_catchup()?
            }
        }
        Ok(CatchupProgress::InProgress)
    }

    fn catchup_step(&mut self, catchup: CatchupRep, node_idx: usize) -> Result<CatchupStepResult, PoolError> {
        let process = self.pending_catchup.as_mut()
            .ok_or(CommonError::InvalidState("Process non-existing CatchUp".to_string()))?;
        process.pending_reps.push((catchup, node_idx));
        process.resp_not_received_node_idx.remove(&node_idx);

        while !process.pending_reps.is_empty() {
            let index = process.pending_reps.get_min_index()?;
            {
                let &mut (ref mut first_resp, node_idx) = process.pending_reps.get_mut(index)
                    .ok_or(CommonError::InvalidStructure(format!("Element not Found")))?;
                if first_resp.min_tx()? - 1 != process.merkle_tree.count() { break; }

                let mut temp_mt = process.merkle_tree.clone();
                while !first_resp.txns.is_empty() {
                    let key = first_resp.min_tx()?.to_string();
                    let new_gen_tx = first_resp.txns.remove(&key).unwrap();
                    if let Ok(new_get_txn_bytes) = rmp_serde::to_vec_named(&new_gen_tx) {
                        temp_mt.append(new_get_txn_bytes)?;
                    } else {
                        return Ok(CatchupStepResult::FailedAtNode(node_idx));
                    }
                }

                if CatchupHandler::check_cons_proofs(&temp_mt, &first_resp.consProof, &self.target_mt_root, self.target_mt_size)
                    .map_err(map_err_err!()).is_err() {
                    return Ok(CatchupStepResult::FailedAtNode(node_idx));
                }

                process.merkle_tree = temp_mt;
            }
            process.pending_reps.remove(index);
        }
        trace!("updated mt hash {}, tree {:?}", process.merkle_tree.root_hash().as_slice().to_base58(), process.merkle_tree);
        if &process.merkle_tree.count() == &self.target_mt_size {
            if process.merkle_tree.root_hash().ne(&self.target_mt_root) {
                return Err(PoolError::CommonError(CommonError::InvalidState(
                    "CatchUp failed: all transactions added, proofs checked, but root hash differ with target".to_string())));
            }
            return Ok(CatchupStepResult::Finished);
        } else {
            return Ok(CatchupStepResult::Continue);
        }
    }

    fn check_cons_proofs(mt: &MerkleTree, cons_proofs: &Vec<String>, target_mt_root: &Vec<u8>, target_mt_size: usize) -> Result<(), CommonError> {
        let mut bytes_proofs: Vec<Vec<u8>> = Vec::new();
        for cons_proof in cons_proofs {
            let cons_proof: &String = cons_proof;
            bytes_proofs.push(cons_proof.from_base58().map_err(|err|
                CommonError::InvalidStructure(
                    format!("Can't decode node consistency proof: {}", err)))?)
        }
        if !mt.consistency_proof(target_mt_root, target_mt_size, &bytes_proofs)? {
            return Err(CommonError::InvalidStructure("Consistency proof verification failed".to_string()));
        }
        Ok(())
    }

    fn finish_catchup(&mut self) -> Result<MerkleTree, PoolError> {
        Ok(self.pending_catchup.take().
            ok_or(CommonError::InvalidState("Try to finish non-existing CatchUp".to_string()))?
            .merkle_tree)
    }

    pub fn flush_requests(&mut self, status: Result<(), PoolError>) -> Result<(), PoolError> {
        if self.initiate_cmd_id == -1 {
            return Ok(());
        }
        let cmd = if self.is_refresh {
            PoolCommand::RefreshAck(self.initiate_cmd_id, status)
        } else {
            PoolCommand::OpenAck(self.initiate_cmd_id, self.pool_id, status)
        };
        self.initiate_cmd_id = -1;
        CommandExecutor::instance()
            .send(Command::Pool(cmd))
            .map_err(|err|
                PoolError::CommonError(
                    CommonError::InvalidState("Can't send ACK cmd".to_string())))
    }

    pub fn get_upcoming_timeout(&self) -> Option<time::Tm> {
        Some(self.timeout)
    }

    pub fn process_timeout(&mut self) -> Result<(), PoolError> {
        let pc = if let Some(pc) = self.pending_catchup.take() { pc } else {
            return Err(PoolError::Timeout);
        };
        warn!("Fail to continue catch-up response(s) not received from nodes with idx {:?}. Node will be blacklisted and catchup will be restarted", pc.resp_not_received_node_idx);
        pc.resp_not_received_node_idx.iter()
            .for_each(|idx| self.nodes[*idx].is_blacklisted = true);
        // TODO may be send ledger status again and re-obtain target MerkleTree params
        self.start_catchup()
    }
}
<commit_msg>Fix catchup issues for blacklisted and updated nodes.<commit_after>extern crate rmp_serde;
extern crate time;

use std::cmp;
use std::collections::HashMap;
use std::ops::Add;

use commands::{Command, CommandExecutor};
use commands::pool::PoolCommand;
use errors::common::CommonError;
use errors::pool::PoolError;
use self::time::Duration;
use super::{
    MerkleTree,
    RemoteNode,
};
use super::rust_base58::{FromBase58, ToBase58};
use super::types::*;

pub const CATCHUP_ROUND_TIMEOUT: i64 = 50;

enum CatchupStepResult {
    Finished,
    Continue,
    FailedAtNode(usize),
}

enum CatchupProgress {
    ShouldBeStarted,
    NotNeeded,
    Finished(MerkleTree),
    InProgress,
}

pub struct CatchupHandler {
    pub f: usize,
    pub ledger_status_same: usize,
    pub merkle_tree: MerkleTree,
    pub target_mt_size: usize,
    pub target_mt_root: Vec<u8>,
    pub new_mt_vote: usize,
    pub nodes: Vec<RemoteNode>,
    pub initiate_cmd_id: i32,
    pub is_refresh: bool,
    pub pending_catchup: Option<CatchUpProcess>,
    pub timeout: time::Tm,
    pub pool_id: i32,
    pub nodes_votes: Vec<Option<(String, usize)>>,
}

impl Default for CatchupHandler {
    fn default() -> Self {
        CatchupHandler {
            f: 0,
            ledger_status_same: 0,
            merkle_tree: MerkleTree::from_vec(Vec::new()).unwrap(),
            nodes: Vec::new(),
            target_mt_size: 0,
            new_mt_vote: 0,
            target_mt_root: Vec::new(),
            pending_catchup: None,
            initiate_cmd_id: 0,
            is_refresh: false,
            pool_id: 0,
            nodes_votes: Vec::new(),
            timeout: time::now_utc(),
        }
    }
}

impl CatchupHandler {
    pub fn process_msg(&mut self, msg: Message, raw_msg: &String, src_ind: usize) -> Result<Option<MerkleTree>, PoolError> {
        let catchup_status: CatchupProgress = match msg {
            Message::Pong => {
                //sending ledger status
                //TODO not send ledger status directly as response on ping, wait pongs from all nodes?
                let ls: LedgerStatus = LedgerStatus {
                    txnSeqNo: self.nodes.len(),
                    merkleRoot: self.merkle_tree.root_hash().as_slice().to_base58(),
                    ledgerId: 0,
                    ppSeqNo: None,
                    viewNo: None,
                };
                let resp_msg: Message = Message::LedgerStatus(ls);
                self.nodes[src_ind].send_msg(&resp_msg)?;
                CatchupProgress::InProgress
            }
            Message::LedgerStatus(ledger_status) => {
                self.nodes_votes[src_ind] = Some((ledger_status.merkleRoot, ledger_status.txnSeqNo));
                self.check_nodes_responses_on_status()?
            }
            Message::ConsistencyProof(cons_proof) => {
                self.nodes_votes[src_ind] = Some((cons_proof.newMerkleRoot, cons_proof.seqNoEnd));
                self.check_nodes_responses_on_status()?
            }
            Message::CatchupRep(catchup) => {
                self.process_catchup_rep(catchup, src_ind)?
            }
            _ => {
                warn!("unhandled msg {:?}", msg);
                CatchupProgress::InProgress
            }
        };

        match catchup_status {
            CatchupProgress::Finished(mt) => return Ok(Some(mt)),
            CatchupProgress::NotNeeded => return Ok(Some(self.merkle_tree.clone())),
            CatchupProgress::ShouldBeStarted => self.start_catchup()?,
            CatchupProgress::InProgress => { /* nothing to do */ }
        }
        Ok(None)
    }

    fn check_nodes_responses_on_status(&mut self) -> Result<CatchupProgress, PoolError> {
        if self.pending_catchup.is_some() {
            return Ok(CatchupProgress::InProgress);
        }
        let mut votes: HashMap<(String, usize), usize> = HashMap::new();
        for node_vote in &self.nodes_votes {
            if let &Some(ref node_vote) = node_vote {
                let cnt = *votes.get(&node_vote).unwrap_or(&0) + 1;
                votes.insert((node_vote.0.clone(), node_vote.1), cnt);
            }
        }
        if let Some((most_popular_vote, votes_cnt)) = votes.iter().max_by_key(|entry| entry.1) {
            if *votes_cnt == self.nodes.len() - self.f {
                let &(ref target_mt_root, target_mt_size) = most_popular_vote;
                let cur_mt_size = self.merkle_tree.count();
                let cur_mt_hash = self.merkle_tree.root_hash().to_base58();
                if target_mt_size == cur_mt_size {
                    if cur_mt_hash.eq(target_mt_root) {
                        return Ok(CatchupProgress::NotNeeded);
                    } else {
                        return Err(PoolError::CommonError(CommonError::InvalidState(
                            "Ledger merkle tree doesn't acceptable for current tree.".to_string())));
                    }
                } else if target_mt_size > cur_mt_size {
                    self.target_mt_size = target_mt_size;
                    self.target_mt_root = target_mt_root.from_base58().map_err(|_|
                        CommonError::InvalidStructure(
                            "Can't parse target MerkleTree hash from nodes responses".to_string()))?;
                    return Ok(CatchupProgress::ShouldBeStarted);
                } else {
                    return Err(PoolError::CommonError(CommonError::InvalidState(
                        "Local merkle tree greater than mt from ledger".to_string())));
                }
            }
        }
        Ok(CatchupProgress::InProgress)
    }

    pub fn reset_nodes_votes(&mut self) {
        self.nodes_votes.clear();
        self.nodes_votes.resize(self.nodes.len(), None);
    }

    pub fn start_catchup(&mut self) -> Result<(), PoolError> {
        trace!("start_catchup");
        if self.pending_catchup.is_some() {
            return Err(PoolError::CommonError(
                CommonError::InvalidState(
                    "CatchUp already started for the pool".to_string())));
        }

        let active_node_cnt = self.nodes.iter().filter(|node| !node.is_blacklisted).count();
        let txns_cnt_in_cur_mt = self.merkle_tree.count();
        let cnt_to_catchup = self.target_mt_size - txns_cnt_in_cur_mt;
        if cnt_to_catchup <= 0 {
            return Err(PoolError::CommonError(CommonError::InvalidState(
                "Nothing to CatchUp, but started".to_string())));
        }

        self.pending_catchup = Some(CatchUpProcess {
            merkle_tree: self.merkle_tree.clone(),
            pending_reps: Vec::new(),
            resp_not_received_node_idx: (0..self.nodes.len()).collect(),
        });
        self.timeout = time::now_utc().add(Duration::seconds(CATCHUP_ROUND_TIMEOUT));

        let portion = (cnt_to_catchup + active_node_cnt - 1) / active_node_cnt; //TODO check standard round up div
        let mut catchup_req = CatchupReq {
            ledgerId: 0,
            seqNoStart: txns_cnt_in_cur_mt + 1,
            seqNoEnd: txns_cnt_in_cur_mt + 1 + portion - 1,
            catchupTill: self.target_mt_size,
        };
        for node in &self.nodes {
            //TODO do not perform duplicate requests, update resp_not_received_node_idx
            if node.is_blacklisted {
                continue;
            }
            node.send_msg(&Message::CatchupReq(catchup_req.clone()))?;
            catchup_req.seqNoStart += portion;
            catchup_req.seqNoEnd = cmp::min(catchup_req.seqNoStart + portion - 1,
                                            catchup_req.catchupTill);
        }
        Ok(())
    }

    fn process_catchup_rep(&mut self, catchup: CatchupRep, node_idx: usize) -> Result<CatchupProgress, PoolError> {
        trace!("append {:?}", catchup);
        let catchup_finished = self.catchup_step(catchup, node_idx)?;
        match catchup_finished {
            CatchupStepResult::Finished => return Ok(CatchupProgress::Finished(self.finish_catchup()?)),
            CatchupStepResult::Continue => { /* nothing to do */ }
            CatchupStepResult::FailedAtNode(failed_node_idx) => {
                warn!("Fail to continue catch-up by response from node with idx {}. Node will be blacklisted and catchup will be restarted", failed_node_idx);
                self.nodes[failed_node_idx].is_blacklisted = true;
                self.pending_catchup = None;
                // TODO may be send ledger status again and re-obtain target MerkleTree params
                self.start_catchup()?
            }
        }
        Ok(CatchupProgress::InProgress)
    }

    fn catchup_step(&mut self, catchup: CatchupRep, node_idx: usize) -> Result<CatchupStepResult, PoolError> {
        let process = self.pending_catchup.as_mut()
            .ok_or(CommonError::InvalidState("Process non-existing CatchUp".to_string()))?;
        process.pending_reps.push((catchup, node_idx));
        process.resp_not_received_node_idx.remove(&node_idx);

        while !process.pending_reps.is_empty() {
            let index = process.pending_reps.get_min_index()?;
            {
                let &mut (ref mut first_resp, node_idx) = process.pending_reps.get_mut(index)
                    .ok_or(CommonError::InvalidStructure(format!("Element not Found")))?;
                if first_resp.min_tx()? - 1 != process.merkle_tree.count() { break; }

                let mut temp_mt = process.merkle_tree.clone();
                while !first_resp.txns.is_empty() {
                    let key = first_resp.min_tx()?.to_string();
                    let new_gen_tx = first_resp.txns.remove(&key).unwrap();
                    if let Ok(new_get_txn_bytes) = rmp_serde::to_vec_named(&new_gen_tx) {
                        temp_mt.append(new_get_txn_bytes)?;
                    } else {
                        return Ok(CatchupStepResult::FailedAtNode(node_idx));
                    }
                }

                if CatchupHandler::check_cons_proofs(&temp_mt, &first_resp.consProof, &self.target_mt_root, self.target_mt_size)
                    .map_err(map_err_err!()).is_err() {
                    return Ok(CatchupStepResult::FailedAtNode(node_idx));
                }

                process.merkle_tree = temp_mt;
            }
            process.pending_reps.remove(index);
        }
        trace!("updated mt hash {}, tree {:?}", process.merkle_tree.root_hash().as_slice().to_base58(), process.merkle_tree);
        if &process.merkle_tree.count() == &self.target_mt_size {
            if process.merkle_tree.root_hash().ne(&self.target_mt_root) {
                return Err(PoolError::CommonError(CommonError::InvalidState(
                    "CatchUp failed: all transactions added, proofs checked, but root hash differ with target".to_string())));
            }
            return Ok(CatchupStepResult::Finished);
        } else {
            return Ok(CatchupStepResult::Continue);
        }
    }

    fn check_cons_proofs(mt: &MerkleTree, cons_proofs: &Vec<String>, target_mt_root: &Vec<u8>, target_mt_size: usize) -> Result<(), CommonError> {
        let mut bytes_proofs: Vec<Vec<u8>> = Vec::new();
        for cons_proof in cons_proofs {
            let cons_proof: &String = cons_proof;
            bytes_proofs.push(cons_proof.from_base58().map_err(|err|
                CommonError::InvalidStructure(
                    format!("Can't decode node consistency proof: {}", err)))?)
        }
        if !mt.consistency_proof(target_mt_root, target_mt_size, &bytes_proofs)? {
            return Err(CommonError::InvalidStructure("Consistency proof verification failed".to_string()));
        }
        Ok(())
    }

    fn finish_catchup(&mut self) -> Result<MerkleTree, PoolError> {
        Ok(self.pending_catchup.take().
            ok_or(CommonError::InvalidState("Try to finish non-existing CatchUp".to_string()))?
            .merkle_tree)
    }

    pub fn flush_requests(&mut self, status: Result<(), PoolError>) -> Result<(), PoolError> {
        if self.initiate_cmd_id == -1 {
            return Ok(());
        }
        let cmd = if self.is_refresh {
            PoolCommand::RefreshAck(self.initiate_cmd_id, status)
        } else {
            PoolCommand::OpenAck(self.initiate_cmd_id, self.pool_id, status)
        };
        self.initiate_cmd_id = -1;
        CommandExecutor::instance()
            .send(Command::Pool(cmd))
            .map_err(|err|
                PoolError::CommonError(
                    CommonError::InvalidState("Can't send ACK cmd".to_string())))
    }

    pub fn get_upcoming_timeout(&self) -> Option<time::Tm> {
        Some(self.timeout)
    }

    pub fn process_timeout(&mut self) -> Result<(), PoolError> {
        let pc = if let Some(pc) = self.pending_catchup.take() { pc } else {
            return Err(PoolError::Timeout);
        };
        warn!("Fail to continue catch-up response(s) not received from nodes with idx {:?}. Node will be blacklisted and catchup will be restarted", pc.resp_not_received_node_idx);
        pc.resp_not_received_node_idx.iter()
            .for_each(|idx| self.nodes[*idx].is_blacklisted = true);
        // TODO may be send ledger status again and re-obtain target MerkleTree params
        self.start_catchup()
    }
}
<|endoftext|>


<commit_before>use crate::pretty_writer::PrettyWriter;
use crate::{
    AbiType, AliasDatatype, AtomType, BindingDirection, BindingParam, Datatype, DatatypeVariant,
    EnumDatatype, FuncBinding, Function, IDLError, MemArea, Package, StructDatatype,
};
use std::io::Write;

/// Generator for the C backend
pub struct CGenerator {
    pub w: PrettyWriter,
}

impl CGenerator {
    pub fn new(w: Box<dyn Write>) -> Self {
        let mut w = PrettyWriter::new(w);
        let prelude = r"
#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>";
        for line in prelude.lines() {
            w.write_line(line.as_ref());
        }
        w.eob();
        Self { w }
    }

    pub fn generate_guest(&mut self, package: &Package) -> Result<(), IDLError> {
        for module in package.modules() {
            for dt in module.datatypes() {
                self.gen_type_header(&dt)?;
                match dt.variant() {
                    DatatypeVariant::Struct(s) => self.gen_struct(&s)?,
                    DatatypeVariant::Alias(a) => self.gen_alias(&a)?,
                    DatatypeVariant::Enum(e) => self.gen_enum(&e)?,
                    DatatypeVariant::Atom(_) => unreachable!(),
                }
            }
            for func in module.functions() {
                self.gen_abi_function(&func)?;
                self.gen_idiomatic_function(&func)?;
            }
        }
        Ok(())
    }

    fn gen_type_header(&mut self, dt: &Datatype) -> Result<(), IDLError> {
        self.w
            .eob()
            .writeln(format!("// ---------- {} ----------", dt.name()))
            .eob();
        Ok(())
    }

    // The most important thing in alias generation is to cache the size
    // and alignment rules of what it ultimately points to
    fn gen_alias(&mut self, alias: &AliasDatatype) -> Result<(), IDLError> {
        let own_type_name = Datatype::from(alias.clone()).c_type_name();
        self.w
            .writeln(format!(
                "typedef {} {};",
                alias.to().c_type_name(),
                own_type_name,
            ))
            .eob();

        // Add an assertion to check that resolved size is the one we computed
        self.w
            .writeln(format!(
                "_Static_assert(sizeof({}) == {}, \"unexpected alias size\");",
                own_type_name,
                alias.mem_size(),
            ))
            .eob();

        Ok(())
    }

    fn gen_struct(&mut self, struct_: &StructDatatype) -> Result<(), IDLError> {
        let own_type_name = Datatype::from(struct_.clone()).c_type_name();
        self.w.writeln(format!("{} {{", own_type_name));
        let mut w_block = self.w.new_block();
        for member in struct_.members() {
            w_block.writeln(format!(
                "{} {};",
                member.type_().c_type_name(),
                member.name(),
            ));
        }
        self.w.writeln("};").eob();

        // Skip the first member, as it will always be at the beginning of the structure
        for member in struct_.members().skip(1) {
            self.w.writeln(format!(
                "_Static_assert(offsetof({}, {}) == {}, \"unexpected offset\");",
                own_type_name,
                member.name(),
                member.offset()
            ));
        }

        self.w
            .writeln(format!(
                "_Static_assert(sizeof({}) == {}, \"unexpected structure size\");",
                own_type_name,
                struct_.mem_size(),
            ))
            .eob();
        Ok(())
    }

    // Enums generate both a specific typedef, and a traditional C-style enum
    // The typedef is required to use a native type which is consistent across all architectures
    fn gen_enum(&mut self, enum_: &EnumDatatype) -> Result<(), IDLError> {
        let own_type_name = Datatype::from(enum_.clone()).c_type_name();
        self.w.writeln(format!("{} {{", own_type_name));
        let mut w = self.w.new_block();
        for variant in enum_.variants() {
            w.writeln(format!(
                "{}, // {}",
                macro_for(enum_.name(), variant.name()),
                variant.index(),
            ));
        }
        self.w.writeln("};").eob();
        self.w
            .writeln(format!(
                "_Static_assert(sizeof({}) == {}, \"unexpected enumeration size\");",
                own_type_name,
                enum_.mem_size(),
            ))
            .eob();
        Ok(())
    }

    fn gen_abi_function(&mut self, func: &Function) -> Result<(), IDLError> {
        let rets = func.rets().collect::<Vec<_>>();
        let return_decl = match rets.len() {
            0 => "void".to_owned(),
            1 => rets[0].type_().c_type_name(),
            _ => unreachable!("functions limited to 0 or 1 return arguments"),
        };

        let arg_list = func
            .args()
            .map(|a| format!("{} {}", a.type_().c_type_name(), a.name()))
            .collect::<Vec<String>>()
            .join(", ");

        self.w.writeln(format!(
            "extern {} {}({}) {};",
            return_decl,
            func.c_abi_func_name(),
            arg_list,
            func.c_abi_func_attributes(),
        ));

        Ok(())
    }

    fn gen_idiomatic_function(&mut self, func: &Function) -> Result<(), IDLError> {
        let ret_bindings = func.c_ret_bindings().collect::<Vec<_>>();

        let own_return_decl = match ret_bindings.len() {
            0 => "void".to_owned(),
            1 => ret_bindings[0].type_().c_type_name(),
            _ => unreachable!("functions limited to 0 or 1 return arguments"),
        };

        let own_arg_list = func
            .c_arg_bindings()
            .map(|b| match b.param() {
                BindingParam::Ptr(_p) => format!(
                    "{}{}* {}",
                    b.c_constness(),
                    b.type_().c_type_name(),
                    b.name()
                ),
                BindingParam::Slice(_ptr, _len) => format!(
                    "{}{}* {}_ptr, size_t {}_len",
                    b.c_constness(),
                    b.type_().c_type_name(),
                    b.name(),
                    b.name(),
                ),
                BindingParam::Value(_v) => format!("{} {}", b.type_().c_type_name(), b.name(),),
            })
            .collect::<Vec<String>>()
            .join(", ");

        self.w.writeln(format!(
            "{} {}({}) {{",
            own_return_decl,
            func.c_idiomatic_func_name(),
            own_arg_list,
        ));
        {
            let arg_bindings = func
                .c_arg_bindings()
                .map(|b| match b.param() {
                    BindingParam::Ptr(p) => format!("({}) {}", p.type_().c_type_name(), b.name()),
                    BindingParam::Slice(p, l) => format!(
                        "({}) {}_ptr, ({}) {}_len",
                        p.type_().c_type_name(),
                        b.name(),
                        l.type_().c_type_name(),
                        b.name()
                    ),
                    BindingParam::Value(v) => format!("({}) {}", v.type_().c_type_name(), b.name()),
                })
                .collect::<Vec<String>>()
                .join(", ");

            let (ret_capture, ret_statement) = match ret_bindings.len() {
                0 => (format!(""), format!("return;")),
                1 => {
                    let b = &ret_bindings[0];
                    match b.param() {
                        BindingParam::Ptr(p) => (
                            format!("{} {} = ", p.type_().c_type_name(), p.name()),
                            format!("return (*{}) {};", b.type_().c_type_name(), p.name()),
                        ),
                        BindingParam::Value(v) => (
                            format!("{} {} = ", v.type_().c_type_name(), v.name()),
                            format!("return ({}) {};", b.type_().c_type_name(), v.name()),
                        ),
                        BindingParam::Slice { .. } => unreachable!(),
                    }
                }
                _ => unreachable!(),
            };

            let mut w = self.w.new_block();
            w.writeln(format!(
                "{}{}({});",
                ret_capture,
                func.c_abi_func_name(),
                arg_bindings,
            ));
            w.writeln(ret_statement);
        }
        self.w.eob().writeln("}");

        Ok(())
    }
}

pub trait CTypeName {
    fn c_type_name(&self) -> String;
}

impl CTypeName for AtomType {
    fn c_type_name(&self) -> String {
        match self {
            AtomType::Bool => "bool",
            AtomType::U8 => "uint8_t",
            AtomType::U16 => "uint16_t",
            AtomType::U32 => "uint32_t",
            AtomType::U64 => "uint64_t",
            AtomType::I8 => "int8_t",
            AtomType::I16 => "int16_t",
            AtomType::I32 => "int32_t",
            AtomType::I64 => "int64_t",
            AtomType::F32 => "float",
            AtomType::F64 => "double",
        }
        .to_owned()
    }
}

impl CTypeName for AbiType {
    fn c_type_name(&self) -> String {
        AtomType::from(self.clone()).c_type_name()
    }
}

impl CTypeName for Datatype<'_> {
    fn c_type_name(&self) -> String {
        match self.variant() {
            DatatypeVariant::Struct(_) => format!("struct {}", self.name()),
            DatatypeVariant::Enum(_) => format!("enum {}", self.name()),
            DatatypeVariant::Alias(_) => self.name().to_owned(),
            DatatypeVariant::Atom(a) => a.c_type_name(),
        }
    }
}

fn macro_for(prefix: &str, name: &str) -> String {
    use heck::ShoutySnakeCase;
    let mut macro_name = String::new();
    macro_name.push_str(&prefix.to_uppercase());
    macro_name.push('_');
    macro_name.push_str(&name.to_shouty_snake_case());
    macro_name
}

impl Function<'_> {
    fn c_abi_func_name(&self) -> String {
        format!("_{}_{}", self.module().name(), self.name())
    }
    fn c_abi_func_attributes(&self) -> String {
        format!(
            "__attribute__((import_module(\"{}\"),import_name(\"{}\")))",
            self.module().name(),
            self.name()
        )
    }
    fn c_idiomatic_func_name(&self) -> String {
        format!("{}_{}", self.module().name(), self.name())
    }

    fn c_arg_bindings<'a>(&'a self) -> impl Iterator<Item = FuncBinding<'a>> {
        self.bindings().filter(|b| !binding_is_ret(b))
    }
    fn c_ret_bindings<'a>(&'a self) -> impl Iterator<Item = FuncBinding<'a>> {
        self.bindings().filter(|b| binding_is_ret(b))
    }
}

fn binding_is_ret(b: &FuncBinding) -> bool {
    b.direction() == BindingDirection::Out && b.param().value().is_some()
}

impl FuncBinding<'_> {
    fn c_constness(&self) -> String {
        if self.direction() == BindingDirection::In
            && (self.param().ptr().is_some() || self.param().slice().is_some())
        {
            "const ".to_owned()
        } else {
            "".to_owned()
        }
    }
}
<commit_msg>lucet-idl: explain c backend unreachable<commit_after>use crate::pretty_writer::PrettyWriter;
use crate::{
    AbiType, AliasDatatype, AtomType, BindingDirection, BindingParam, Datatype, DatatypeVariant,
    EnumDatatype, FuncBinding, Function, IDLError, MemArea, Package, StructDatatype,
};
use std::io::Write;

/// Generator for the C backend
pub struct CGenerator {
    pub w: PrettyWriter,
}

impl CGenerator {
    pub fn new(w: Box<dyn Write>) -> Self {
        let mut w = PrettyWriter::new(w);
        let prelude = r"
#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>";
        for line in prelude.lines() {
            w.write_line(line.as_ref());
        }
        w.eob();
        Self { w }
    }

    pub fn generate_guest(&mut self, package: &Package) -> Result<(), IDLError> {
        for module in package.modules() {
            for dt in module.datatypes() {
                self.gen_type_header(&dt)?;
                match dt.variant() {
                    DatatypeVariant::Struct(s) => self.gen_struct(&s)?,
                    DatatypeVariant::Alias(a) => self.gen_alias(&a)?,
                    DatatypeVariant::Enum(e) => self.gen_enum(&e)?,
                    DatatypeVariant::Atom(_) => {
                        unreachable!("atoms should not be defined in package modules")
                    }
                }
            }
            for func in module.functions() {
                self.gen_abi_function(&func)?;
                self.gen_idiomatic_function(&func)?;
            }
        }
        Ok(())
    }

    fn gen_type_header(&mut self, dt: &Datatype) -> Result<(), IDLError> {
        self.w
            .eob()
            .writeln(format!("// ---------- {} ----------", dt.name()))
            .eob();
        Ok(())
    }

    // The most important thing in alias generation is to cache the size
    // and alignment rules of what it ultimately points to
    fn gen_alias(&mut self, alias: &AliasDatatype) -> Result<(), IDLError> {
        let own_type_name = Datatype::from(alias.clone()).c_type_name();
        self.w
            .writeln(format!(
                "typedef {} {};",
                alias.to().c_type_name(),
                own_type_name,
            ))
            .eob();

        // Add an assertion to check that resolved size is the one we computed
        self.w
            .writeln(format!(
                "_Static_assert(sizeof({}) == {}, \"unexpected alias size\");",
                own_type_name,
                alias.mem_size(),
            ))
            .eob();

        Ok(())
    }

    fn gen_struct(&mut self, struct_: &StructDatatype) -> Result<(), IDLError> {
        let own_type_name = Datatype::from(struct_.clone()).c_type_name();
        self.w.writeln(format!("{} {{", own_type_name));
        let mut w_block = self.w.new_block();
        for member in struct_.members() {
            w_block.writeln(format!(
                "{} {};",
                member.type_().c_type_name(),
                member.name(),
            ));
        }
        self.w.writeln("};").eob();

        // Skip the first member, as it will always be at the beginning of the structure
        for member in struct_.members().skip(1) {
            self.w.writeln(format!(
                "_Static_assert(offsetof({}, {}) == {}, \"unexpected offset\");",
                own_type_name,
                member.name(),
                member.offset()
            ));
        }

        self.w
            .writeln(format!(
                "_Static_assert(sizeof({}) == {}, \"unexpected structure size\");",
                own_type_name,
                struct_.mem_size(),
            ))
            .eob();
        Ok(())
    }

    // Enums generate both a specific typedef, and a traditional C-style enum
    // The typedef is required to use a native type which is consistent across all architectures
    fn gen_enum(&mut self, enum_: &EnumDatatype) -> Result<(), IDLError> {
        let own_type_name = Datatype::from(enum_.clone()).c_type_name();
        self.w.writeln(format!("{} {{", own_type_name));
        let mut w = self.w.new_block();
        for variant in enum_.variants() {
            w.writeln(format!(
                "{}, // {}",
                macro_for(enum_.name(), variant.name()),
                variant.index(),
            ));
        }
        self.w.writeln("};").eob();
        self.w
            .writeln(format!(
                "_Static_assert(sizeof({}) == {}, \"unexpected enumeration size\");",
                own_type_name,
                enum_.mem_size(),
            ))
            .eob();
        Ok(())
    }

    fn gen_abi_function(&mut self, func: &Function) -> Result<(), IDLError> {
        let rets = func.rets().collect::<Vec<_>>();
        let return_decl = match rets.len() {
            0 => "void".to_owned(),
            1 => rets[0].type_().c_type_name(),
            _ => unreachable!("functions limited to 0 or 1 return arguments"),
        };

        let arg_list = func
            .args()
            .map(|a| format!("{} {}", a.type_().c_type_name(), a.name()))
            .collect::<Vec<String>>()
            .join(", ");

        self.w.writeln(format!(
            "extern {} {}({}) {};",
            return_decl,
            func.c_abi_func_name(),
            arg_list,
            func.c_abi_func_attributes(),
        ));

        Ok(())
    }

    fn gen_idiomatic_function(&mut self, func: &Function) -> Result<(), IDLError> {
        let ret_bindings = func.c_ret_bindings().collect::<Vec<_>>();

        let own_return_decl = match ret_bindings.len() {
            0 => "void".to_owned(),
            1 => ret_bindings[0].type_().c_type_name(),
            _ => unreachable!("functions limited to 0 or 1 return arguments"),
        };

        let own_arg_list = func
            .c_arg_bindings()
            .map(|b| match b.param() {
                BindingParam::Ptr(_p) => format!(
                    "{}{}* {}",
                    b.c_constness(),
                    b.type_().c_type_name(),
                    b.name()
                ),
                BindingParam::Slice(_ptr, _len) => format!(
                    "{}{}* {}_ptr, size_t {}_len",
                    b.c_constness(),
                    b.type_().c_type_name(),
                    b.name(),
                    b.name(),
                ),
                BindingParam::Value(_v) => format!("{} {}", b.type_().c_type_name(), b.name(),),
            })
            .collect::<Vec<String>>()
            .join(", ");

        self.w.writeln(format!(
            "{} {}({}) {{",
            own_return_decl,
            func.c_idiomatic_func_name(),
            own_arg_list,
        ));
        {
            let arg_bindings = func
                .c_arg_bindings()
                .map(|b| match b.param() {
                    BindingParam::Ptr(p) => format!("({}) {}", p.type_().c_type_name(), b.name()),
                    BindingParam::Slice(p, l) => format!(
                        "({}) {}_ptr, ({}) {}_len",
                        p.type_().c_type_name(),
                        b.name(),
                        l.type_().c_type_name(),
                        b.name()
                    ),
                    BindingParam::Value(v) => format!("({}) {}", v.type_().c_type_name(), b.name()),
                })
                .collect::<Vec<String>>()
                .join(", ");

            let (ret_capture, ret_statement) = match ret_bindings.len() {
                0 => (format!(""), format!("return;")),
                1 => {
                    let b = &ret_bindings[0];
                    match b.param() {
                        BindingParam::Ptr(p) => (
                            format!("{} {} = ", p.type_().c_type_name(), p.name()),
                            format!("return (*{}) {};", b.type_().c_type_name(), p.name()),
                        ),
                        BindingParam::Value(v) => (
                            format!("{} {} = ", v.type_().c_type_name(), v.name()),
                            format!("return ({}) {};", b.type_().c_type_name(), v.name()),
                        ),
                        BindingParam::Slice { .. } => unreachable!(),
                    }
                }
                _ => unreachable!(),
            };

            let mut w = self.w.new_block();
            w.writeln(format!(
                "{}{}({});",
                ret_capture,
                func.c_abi_func_name(),
                arg_bindings,
            ));
            w.writeln(ret_statement);
        }
        self.w.eob().writeln("}");

        Ok(())
    }
}

pub trait CTypeName {
    fn c_type_name(&self) -> String;
}

impl CTypeName for AtomType {
    fn c_type_name(&self) -> String {
        match self {
            AtomType::Bool => "bool",
            AtomType::U8 => "uint8_t",
            AtomType::U16 => "uint16_t",
            AtomType::U32 => "uint32_t",
            AtomType::U64 => "uint64_t",
            AtomType::I8 => "int8_t",
            AtomType::I16 => "int16_t",
            AtomType::I32 => "int32_t",
            AtomType::I64 => "int64_t",
            AtomType::F32 => "float",
            AtomType::F64 => "double",
        }
        .to_owned()
    }
}

impl CTypeName for AbiType {
    fn c_type_name(&self) -> String {
        AtomType::from(self.clone()).c_type_name()
    }
}

impl CTypeName for Datatype<'_> {
    fn c_type_name(&self) -> String {
        match self.variant() {
            DatatypeVariant::Struct(_) => format!("struct {}", self.name()),
            DatatypeVariant::Enum(_) => format!("enum {}", self.name()),
            DatatypeVariant::Alias(_) => self.name().to_owned(),
            DatatypeVariant::Atom(a) => a.c_type_name(),
        }
    }
}

fn macro_for(prefix: &str, name: &str) -> String {
    use heck::ShoutySnakeCase;
    let mut macro_name = String::new();
    macro_name.push_str(&prefix.to_uppercase());
    macro_name.push('_');
    macro_name.push_str(&name.to_shouty_snake_case());
    macro_name
}

impl Function<'_> {
    fn c_abi_func_name(&self) -> String {
        format!("_{}_{}", self.module().name(), self.name())
    }
    fn c_abi_func_attributes(&self) -> String {
        format!(
            "__attribute__((import_module(\"{}\"),import_name(\"{}\")))",
            self.module().name(),
            self.name()
        )
    }
    fn c_idiomatic_func_name(&self) -> String {
        format!("{}_{}", self.module().name(), self.name())
    }

    fn c_arg_bindings<'a>(&'a self) -> impl Iterator<Item = FuncBinding<'a>> {
        self.bindings().filter(|b| !binding_is_ret(b))
    }
    fn c_ret_bindings<'a>(&'a self) -> impl Iterator<Item = FuncBinding<'a>> {
        self.bindings().filter(|b| binding_is_ret(b))
    }
}

fn binding_is_ret(b: &FuncBinding) -> bool {
    b.direction() == BindingDirection::Out && b.param().value().is_some()
}

impl FuncBinding<'_> {
    fn c_constness(&self) -> String {
        if self.direction() == BindingDirection::In
            && (self.param().ptr().is_some() || self.param().slice().is_some())
        {
            "const ".to_owned()
        } else {
            "".to_owned()
        }
    }
}
<|endoftext|>


<commit_before>use crate::os::raw::c_int;

mod fs;
pub mod sockets;
pub use self::fs::*;

pub const SOLID_BP_PROGRAM_EXITED: usize = 15;
pub const SOLID_BP_CSABORT: usize = 16;

#[inline(always)]
pub fn breakpoint_program_exited(tid: usize) {
    unsafe {
        match () {
            #[cfg(target_arch = "arm")]
            () => asm!("bkpt #{}", const SOLID_BP_PROGRAM_EXITED, in("r0") tid),
            #[cfg(target_arch = "aarch64")]
            () => asm!("hlt #{}", const SOLID_BP_PROGRAM_EXITED, in("x0") tid),
        }
    }
}

#[inline(always)]
pub fn breakpoint_abort() {
    unsafe {
        match () {
            #[cfg(target_arch = "arm")]
            () => asm!("bkpt #{}", const SOLID_BP_CSABORT),
            #[cfg(target_arch = "aarch64")]
            () => asm!("hlt #{}", const SOLID_BP_CSABORT),
        }
    }
}

// `solid_types.h`
pub use super::itron::abi::{ER, ER_ID, E_TMOUT, ID};

pub const SOLID_ERR_NOTFOUND: ER = -1000;
pub const SOLID_ERR_NOTSUPPORTED: ER = -1001;
pub const SOLID_ERR_EBADF: ER = -1002;
pub const SOLID_ERR_INVALIDCONTENT: ER = -1003;
pub const SOLID_ERR_NOTUSED: ER = -1004;
pub const SOLID_ERR_ALREADYUSED: ER = -1005;
pub const SOLID_ERR_OUTOFBOUND: ER = -1006;
pub const SOLID_ERR_BADSEQUENCE: ER = -1007;
pub const SOLID_ERR_UNKNOWNDEVICE: ER = -1008;
pub const SOLID_ERR_BUSY: ER = -1009;
pub const SOLID_ERR_TIMEOUT: ER = -1010;
pub const SOLID_ERR_INVALIDACCESS: ER = -1011;
pub const SOLID_ERR_NOTREADY: ER = -1012;

// `solid_rtc.h`
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct SOLID_RTC_TIME {
    pub tm_sec: c_int,
    pub tm_min: c_int,
    pub tm_hour: c_int,
    pub tm_mday: c_int,
    pub tm_mon: c_int,
    pub tm_year: c_int,
    pub tm_wday: c_int,
}

extern "C" {
    pub fn SOLID_RTC_ReadTime(time: *mut SOLID_RTC_TIME) -> c_int;
}

// `solid_log.h`
extern "C" {
    pub fn SOLID_LOG_write(s: *const u8, l: usize);
}

// `solid_mem.h`
extern "C" {
    pub fn SOLID_TLS_AddDestructor(id: i32, dtor: unsafe extern "C" fn(*mut u8));
}

// `solid_rng.h`
extern "C" {
    pub fn SOLID_RNG_SampleRandomBytes(buffer: *mut u8, length: usize) -> c_int;
}

// `rwlock.h`
extern "C" {
    pub fn rwl_loc_rdl(id: ID) -> ER;
    pub fn rwl_loc_wrl(id: ID) -> ER;
    pub fn rwl_ploc_rdl(id: ID) -> ER;
    pub fn rwl_ploc_wrl(id: ID) -> ER;
    pub fn rwl_unl_rwl(id: ID) -> ER;
    pub fn rwl_acre_rwl() -> ER_ID;
    pub fn rwl_del_rwl(id: ID) -> ER;
}
<commit_msg>Rollup merge of #90690 - solid-rs:fix-kmc-solid-asm-const, r=Mark-Simulacrum<commit_after>use crate::os::raw::c_int;

mod fs;
pub mod sockets;
pub use self::fs::*;

#[inline(always)]
pub fn breakpoint_program_exited(tid: usize) {
    unsafe {
        match () {
            // SOLID_BP_PROGRAM_EXITED = 15
            #[cfg(target_arch = "arm")]
            () => asm!("bkpt #15", in("r0") tid),
            #[cfg(target_arch = "aarch64")]
            () => asm!("hlt #15", in("x0") tid),
        }
    }
}

#[inline(always)]
pub fn breakpoint_abort() {
    unsafe {
        match () {
            // SOLID_BP_CSABORT = 16
            #[cfg(target_arch = "arm")]
            () => asm!("bkpt #16"),
            #[cfg(target_arch = "aarch64")]
            () => asm!("hlt #16"),
        }
    }
}

// `solid_types.h`
pub use super::itron::abi::{ER, ER_ID, E_TMOUT, ID};

pub const SOLID_ERR_NOTFOUND: ER = -1000;
pub const SOLID_ERR_NOTSUPPORTED: ER = -1001;
pub const SOLID_ERR_EBADF: ER = -1002;
pub const SOLID_ERR_INVALIDCONTENT: ER = -1003;
pub const SOLID_ERR_NOTUSED: ER = -1004;
pub const SOLID_ERR_ALREADYUSED: ER = -1005;
pub const SOLID_ERR_OUTOFBOUND: ER = -1006;
pub const SOLID_ERR_BADSEQUENCE: ER = -1007;
pub const SOLID_ERR_UNKNOWNDEVICE: ER = -1008;
pub const SOLID_ERR_BUSY: ER = -1009;
pub const SOLID_ERR_TIMEOUT: ER = -1010;
pub const SOLID_ERR_INVALIDACCESS: ER = -1011;
pub const SOLID_ERR_NOTREADY: ER = -1012;

// `solid_rtc.h`
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct SOLID_RTC_TIME {
    pub tm_sec: c_int,
    pub tm_min: c_int,
    pub tm_hour: c_int,
    pub tm_mday: c_int,
    pub tm_mon: c_int,
    pub tm_year: c_int,
    pub tm_wday: c_int,
}

extern "C" {
    pub fn SOLID_RTC_ReadTime(time: *mut SOLID_RTC_TIME) -> c_int;
}

// `solid_log.h`
extern "C" {
    pub fn SOLID_LOG_write(s: *const u8, l: usize);
}

// `solid_mem.h`
extern "C" {
    pub fn SOLID_TLS_AddDestructor(id: i32, dtor: unsafe extern "C" fn(*mut u8));
}

// `solid_rng.h`
extern "C" {
    pub fn SOLID_RNG_SampleRandomBytes(buffer: *mut u8, length: usize) -> c_int;
}

// `rwlock.h`
extern "C" {
    pub fn rwl_loc_rdl(id: ID) -> ER;
    pub fn rwl_loc_wrl(id: ID) -> ER;
    pub fn rwl_ploc_rdl(id: ID) -> ER;
    pub fn rwl_ploc_wrl(id: ID) -> ER;
    pub fn rwl_unl_rwl(id: ID) -> ER;
    pub fn rwl_acre_rwl() -> ER_ID;
    pub fn rwl_del_rwl(id: ID) -> ER;
}
<|endoftext|>


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

use regex::Regex;

use super::file::header::data::FileHeaderData;

pub struct ParserError {
    summary: String,
    parsertext: String,
    index: i32,
    explanation: Option<String>,
    caused_by: Option<Box<Error>>,
}

impl ParserError {
    pub fn new(sum: &'static str, text: String, idx: i32, expl: &'static str) -> ParserError {
        ParserError {
            summary: String::from(sum),
            parsertext: text,
            index: idx,
            explanation: Some(String::from(expl)),
            caused_by: None,
        }
    }

    pub fn short(sum: &str, text: String, idx: i32) -> ParserError {
        ParserError {
            summary: String::from(sum),
            parsertext: text,
            index: idx,
            explanation: None,
            caused_by: None,
        }
    }

    pub fn with_cause(mut self, e: Box<Error>) -> ParserError {
        self.caused_by = Some(e);
        self
    }

}

impl Error for ParserError {

    fn description(&self) -> &str {
        &self.summary[..]
    }

    fn cause(&self) -> Option<&Error> {
        self.caused_by.as_ref().map(|e| &**e)
    }

}

impl Debug for ParserError {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        try!(write!(fmt, "ParserError: {}\n\n", self.summary));

        if let Some(ref e) = self.explanation {
            try!(write!(fmt, "{}\n\n", e));
        }

        try!(write!(fmt, "On position {}\nin\n{}", self.index, self.parsertext));
        Ok(())
    }

}

impl Display for ParserError {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        try!(write!(fmt, "ParserError: {}", self.summary));

        if let Some(ref e) = self.explanation {
            try!(write!(fmt, "\n\n{}", e));
        }

        Ok(())
    }

}

/**
 * Trait for a header parser.
 *
 * This parser type has to provide two functions:
 *  - read(), which reads an String into a FileHeaderData structure
 *  - write(), which parses a FileHeaderData structure into a String
 *
 * TODO: Use Write/Read traits?
 */
pub trait FileHeaderParser : Sized + Debug + Display {
    fn read(&self, string: Option<String>) -> Result<FileHeaderData, ParserError>;
    fn write(&self, data: &FileHeaderData) -> Result<String, ParserError>;
}

/**
 * Parser
 *
 * This Parser object is an abstraction which uses the FileHeaderParser to parse the whole contents
 * of a file into a header (FileHeaderData) structure and the content (String).
 */
pub struct Parser<HP> {
    headerp : HP,
}

impl<HP: FileHeaderParser> Parser<HP> {

    pub fn new(headerp: HP) -> Parser<HP> {
        Parser {
            headerp: headerp,
        }
    }

    /**
     * Read the String which is the contents of a file into a (FileHeaderData, String) tuple, which
     * is the header and the content of the file.
     */
    pub fn read(&self, s: String) -> Result<(FileHeaderData, String), ParserError> {
        debug!("Reading into internal datastructure: '{}'", s);
        let divided = self.divide_text(&s);

        if divided.is_err() {
            debug!("Error reading into internal datastructure");
            let mut p = ParserError::new("Dividing text failed",
                                         s, 0,
                    "Dividing text with divide_text() failed");
            return Err(p.with_cause(Box::new(divided.err().unwrap())));
        }

        let (header, data) = divided.ok().unwrap();
        debug!("Header = '{:?}'", header);
        debug!("Data   = '{:?}'", data);

        let h_parseres = try!(self.headerp.read(header));
        debug!("Success parsing header");

        Ok((h_parseres, data.unwrap_or(String::new())))
    }

    /**
     * Write the FileHeaderData and String (header and content) of the tuple into a String, which
     * can then simply be written into the store as a file.
     */
    pub fn write(&self, tpl : (&FileHeaderData, &String)) -> Result<String, ParserError> {
        debug!("Parsing internal datastructure to String");
        let (header, data) = tpl;
        let h_text = try!(self.headerp.write(&header));
        debug!("Success translating header");

        let text = format!("---\n{}\n---\n{}", h_text, data);
        Ok(text)
    }

    /**
     * Helper to parse the full-text of a file into a header part (String) and a content part
     * (String)
     */
    fn divide_text(&self, text: &String) -> Result<(Option<String>, Option<String>), ParserError> {
        let re = Regex::new(r"(?sm)^---$(.*)^---$(.*)").unwrap();

        debug!("Splitting: '{}'", text);
        debug!("   regex = {:?}", re);

        re.captures(text).map(|captures| {

            if captures.len() != 3 {
                debug!("Unexpected amount of captures");
                return Err(ParserError::new("Unexpected Regex output",
                                            text.clone(), 0,
                                            "The regex to divide text into header and content had an unexpected output."))
            }

            let header  = captures.at(1).map(|s| String::from(s));
            let content = captures.at(2).map(|s| String::from(s));

            debug!("Splitted, Header = '{:?}'", header.clone().unwrap_or("NONE".into()));
            debug!("Splitted, Data   = '{:?}'", content.clone().unwrap_or("NONE".into()));
            Ok((header, content))
        }).or_else(|| {
            debug!("Cannot capture from text");
            let e = ParserError::new("Cannot run regex on text",
                                     text.clone(), 0,
                                     "Cannot run regex on text to divide it into header and content.");
            Some(Err(e))
        }).unwrap()
    }

}

impl<HP> Debug for Parser<HP>
    where HP: FileHeaderParser
{

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        try!(write!(fmt, "Parser<{:?}>", self.headerp));
        Ok(())
    }

}
<commit_msg>Remove unneeded Keyword "mut"<commit_after>use std::error::Error;
use std::fmt::{Debug, Display, Formatter};
use std::fmt;

use regex::Regex;

use super::file::header::data::FileHeaderData;

pub struct ParserError {
    summary: String,
    parsertext: String,
    index: i32,
    explanation: Option<String>,
    caused_by: Option<Box<Error>>,
}

impl ParserError {
    pub fn new(sum: &'static str, text: String, idx: i32, expl: &'static str) -> ParserError {
        ParserError {
            summary: String::from(sum),
            parsertext: text,
            index: idx,
            explanation: Some(String::from(expl)),
            caused_by: None,
        }
    }

    pub fn short(sum: &str, text: String, idx: i32) -> ParserError {
        ParserError {
            summary: String::from(sum),
            parsertext: text,
            index: idx,
            explanation: None,
            caused_by: None,
        }
    }

    pub fn with_cause(mut self, e: Box<Error>) -> ParserError {
        self.caused_by = Some(e);
        self
    }

}

impl Error for ParserError {

    fn description(&self) -> &str {
        &self.summary[..]
    }

    fn cause(&self) -> Option<&Error> {
        self.caused_by.as_ref().map(|e| &**e)
    }

}

impl Debug for ParserError {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        try!(write!(fmt, "ParserError: {}\n\n", self.summary));

        if let Some(ref e) = self.explanation {
            try!(write!(fmt, "{}\n\n", e));
        }

        try!(write!(fmt, "On position {}\nin\n{}", self.index, self.parsertext));
        Ok(())
    }

}

impl Display for ParserError {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        try!(write!(fmt, "ParserError: {}", self.summary));

        if let Some(ref e) = self.explanation {
            try!(write!(fmt, "\n\n{}", e));
        }

        Ok(())
    }

}

/**
 * Trait for a header parser.
 *
 * This parser type has to provide two functions:
 *  - read(), which reads an String into a FileHeaderData structure
 *  - write(), which parses a FileHeaderData structure into a String
 *
 * TODO: Use Write/Read traits?
 */
pub trait FileHeaderParser : Sized + Debug + Display {
    fn read(&self, string: Option<String>) -> Result<FileHeaderData, ParserError>;
    fn write(&self, data: &FileHeaderData) -> Result<String, ParserError>;
}

/**
 * Parser
 *
 * This Parser object is an abstraction which uses the FileHeaderParser to parse the whole contents
 * of a file into a header (FileHeaderData) structure and the content (String).
 */
pub struct Parser<HP> {
    headerp : HP,
}

impl<HP: FileHeaderParser> Parser<HP> {

    pub fn new(headerp: HP) -> Parser<HP> {
        Parser {
            headerp: headerp,
        }
    }

    /**
     * Read the String which is the contents of a file into a (FileHeaderData, String) tuple, which
     * is the header and the content of the file.
     */
    pub fn read(&self, s: String) -> Result<(FileHeaderData, String), ParserError> {
        debug!("Reading into internal datastructure: '{}'", s);
        let divided = self.divide_text(&s);

        if divided.is_err() {
            debug!("Error reading into internal datastructure");
            let p = ParserError::new("Dividing text failed", s, 0,
                                     "Dividing text with divide_text() failed");
            return Err(p.with_cause(Box::new(divided.err().unwrap())));
        }

        let (header, data) = divided.ok().unwrap();
        debug!("Header = '{:?}'", header);
        debug!("Data   = '{:?}'", data);

        let h_parseres = try!(self.headerp.read(header));
        debug!("Success parsing header");

        Ok((h_parseres, data.unwrap_or(String::new())))
    }

    /**
     * Write the FileHeaderData and String (header and content) of the tuple into a String, which
     * can then simply be written into the store as a file.
     */
    pub fn write(&self, tpl : (&FileHeaderData, &String)) -> Result<String, ParserError> {
        debug!("Parsing internal datastructure to String");
        let (header, data) = tpl;
        let h_text = try!(self.headerp.write(&header));
        debug!("Success translating header");

        let text = format!("---\n{}\n---\n{}", h_text, data);
        Ok(text)
    }

    /**
     * Helper to parse the full-text of a file into a header part (String) and a content part
     * (String)
     */
    fn divide_text(&self, text: &String) -> Result<(Option<String>, Option<String>), ParserError> {
        let re = Regex::new(r"(?sm)^---$(.*)^---$(.*)").unwrap();

        debug!("Splitting: '{}'", text);
        debug!("   regex = {:?}", re);

        re.captures(text).map(|captures| {

            if captures.len() != 3 {
                debug!("Unexpected amount of captures");
                return Err(ParserError::new("Unexpected Regex output",
                                            text.clone(), 0,
                                            "The regex to divide text into header and content had an unexpected output."))
            }

            let header  = captures.at(1).map(|s| String::from(s));
            let content = captures.at(2).map(|s| String::from(s));

            debug!("Splitted, Header = '{:?}'", header.clone().unwrap_or("NONE".into()));
            debug!("Splitted, Data   = '{:?}'", content.clone().unwrap_or("NONE".into()));
            Ok((header, content))
        }).or_else(|| {
            debug!("Cannot capture from text");
            let e = ParserError::new("Cannot run regex on text",
                                     text.clone(), 0,
                                     "Cannot run regex on text to divide it into header and content.");
            Some(Err(e))
        }).unwrap()
    }

}

impl<HP> Debug for Parser<HP>
    where HP: FileHeaderParser
{

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        try!(write!(fmt, "Parser<{:?}>", self.headerp));
        Ok(())
    }

}
<|endoftext|>


<commit_before>extern crate tempdir;

extern crate grpc_compiler;

extern crate protobuf;
extern crate protoc;
extern crate protoc_rust;

use std::fs;
use std::io;
use std::io::Read;
use std::io::Write;

pub type Error = io::Error;
pub type Result<T> = io::Result<T>;

#[derive(Debug, Default)]
pub struct Args<'a> {
    /// --lang_out= param
    pub out_dir: &'a str,
    /// -I args
    pub includes: &'a [&'a str],
    /// List of .proto files to compile
    pub input: &'a [&'a str],
    /// Generate rust-protobuf files along with rust-gprc
    pub rust_protobuf: bool,
}

pub fn run(args: Args) -> Result<()> {
    let protoc = protoc::Protoc::from_env_path();
    let version = protoc.version().expect("protoc version");
    if !version.is_3() {
        panic!("protobuf must have version 3");
    }

    if args.rust_protobuf {
        protoc_rust::run(protoc_rust::Args {
            out_dir: args.out_dir,
            includes: args.includes,
            input: args.input,
            ..Default::default()
        })?;
    }

    let temp_dir = tempdir::TempDir::new("protoc-rust")?;
    let temp_file = temp_dir.path().join("descriptor.pbbin");
    let temp_file = temp_file.to_str().expect("utf-8 file name");

    protoc.write_descriptor_set(protoc::DescriptorSetOutArgs {
        out: temp_file,
        includes: args.includes,
        input: args.input,
        include_imports: true,
    })?;

    let mut fds = Vec::new();
    let mut file = fs::File::open(temp_file)?;
    file.read_to_end(&mut fds)?;

    drop(file);
    drop(temp_dir);

    let fds: protobuf::descriptor::FileDescriptorSet =
        protobuf::parse_from_bytes(&fds).map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;

    let mut includes = args.includes;
    if includes.is_empty() {
        static DOT_SLICE: &'static [&'static str] = &["."];
        includes = DOT_SLICE;
    }

    let mut files_to_generate = Vec::new();
    'outer: for file in args.input {
        for include in includes {
            if let Some(truncated) = remove_path_prefix(file, include) {
                files_to_generate.push(truncated.to_owned());
                continue 'outer;
            }
        }

        return Err(Error::new(
            io::ErrorKind::Other,
            format!(
                "file {:?} is not found in includes {:?}",
                file, args.includes
            ),
        ));
    }

    let gen_result = grpc_compiler::codegen::gen(fds.get_file(), &files_to_generate);

    for r in gen_result {
        let r: protobuf::compiler_plugin::GenResult = r;
        let file = format!("{}/{}", args.out_dir, r.name);
        let mut file = fs::File::create(&file)?;
        file.write_all(&r.content)?;
        file.flush()?;
    }

    Ok(())
}

fn remove_dot_slash(path: &str) -> &str {
    if path == "." {
        ""
    } else if path.starts_with("./") || path.starts_with(".\\") {
        &path[2..]
    } else {
        path
    }
}

fn remove_path_prefix<'a>(mut path: &'a str, mut prefix: &str) -> Option<&'a str> {
    path = remove_dot_slash(path);
    prefix = remove_dot_slash(prefix);

    if prefix == "" {
        return Some(path);
    }

    if prefix.ends_with("/") || prefix.ends_with("\\") {
        prefix = &prefix[..prefix.len() - 1];
    }

    if !path.starts_with(prefix) {
        return None;
    }

    if path.len() <= prefix.len() {
        return None;
    }

    if path.as_bytes()[prefix.len()] == b'/' || path.as_bytes()[prefix.len()] == b'\\' {
        return Some(&path[prefix.len() + 1..]);
    } else {
        return None;
    }
}

#[cfg(test)]
mod test {
    #[test]
    fn remove_path_prefix() {
        assert_eq!(
            Some("abc.proto"),
            super::remove_path_prefix("xxx/abc.proto", "xxx")
        );
        assert_eq!(
            Some("abc.proto"),
            super::remove_path_prefix("xxx/abc.proto", "xxx/")
        );
        assert_eq!(
            Some("abc.proto"),
            super::remove_path_prefix("../xxx/abc.proto", "../xxx/")
        );
        assert_eq!(
            Some("abc.proto"),
            super::remove_path_prefix("abc.proto", ".")
        );
        assert_eq!(
            Some("abc.proto"),
            super::remove_path_prefix("abc.proto", "./")
        );
        assert_eq!(None, super::remove_path_prefix("xxx/abc.proto", "yyy"));
        assert_eq!(None, super::remove_path_prefix("xxx/abc.proto", "yyy/"));
    }
}
<commit_msg>Allow customization of rust-protobuf code<commit_after>extern crate tempdir;

extern crate grpc_compiler;

extern crate protobuf;
extern crate protoc;
extern crate protoc_rust;

use std::fs;
use std::io;
use std::io::Read;
use std::io::Write;

pub type Error = io::Error;
pub type Result<T> = io::Result<T>;

#[derive(Debug, Default)]
pub struct Args<'a> {
    /// --lang_out= param
    pub out_dir: &'a str,
    /// -I args
    pub includes: &'a [&'a str],
    /// List of .proto files to compile
    pub input: &'a [&'a str],
    /// Generate rust-protobuf files along with rust-gprc
    pub rust_protobuf: bool,
    /// Customize rust-protobuf codegen
    pub rust_protobuf_customize: protoc_rust::Customize,
}

pub fn run(args: Args) -> Result<()> {
    let protoc = protoc::Protoc::from_env_path();
    let version = protoc.version().expect("protoc version");
    if !version.is_3() {
        panic!("protobuf must have version 3");
    }

    if args.rust_protobuf {
        protoc_rust::run(protoc_rust::Args {
            out_dir: args.out_dir,
            includes: args.includes,
            input: args.input,
            customize: args.rust_protobuf_customize,
            ..Default::default()
        })?;
    }

    let temp_dir = tempdir::TempDir::new("protoc-rust")?;
    let temp_file = temp_dir.path().join("descriptor.pbbin");
    let temp_file = temp_file.to_str().expect("utf-8 file name");

    protoc.write_descriptor_set(protoc::DescriptorSetOutArgs {
        out: temp_file,
        includes: args.includes,
        input: args.input,
        include_imports: true,
    })?;

    let mut fds = Vec::new();
    let mut file = fs::File::open(temp_file)?;
    file.read_to_end(&mut fds)?;

    drop(file);
    drop(temp_dir);

    let fds: protobuf::descriptor::FileDescriptorSet =
        protobuf::parse_from_bytes(&fds).map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;

    let mut includes = args.includes;
    if includes.is_empty() {
        static DOT_SLICE: &'static [&'static str] = &["."];
        includes = DOT_SLICE;
    }

    let mut files_to_generate = Vec::new();
    'outer: for file in args.input {
        for include in includes {
            if let Some(truncated) = remove_path_prefix(file, include) {
                files_to_generate.push(truncated.to_owned());
                continue 'outer;
            }
        }

        return Err(Error::new(
            io::ErrorKind::Other,
            format!(
                "file {:?} is not found in includes {:?}",
                file, args.includes
            ),
        ));
    }

    let gen_result = grpc_compiler::codegen::gen(fds.get_file(), &files_to_generate);

    for r in gen_result {
        let r: protobuf::compiler_plugin::GenResult = r;
        let file = format!("{}/{}", args.out_dir, r.name);
        let mut file = fs::File::create(&file)?;
        file.write_all(&r.content)?;
        file.flush()?;
    }

    Ok(())
}

fn remove_dot_slash(path: &str) -> &str {
    if path == "." {
        ""
    } else if path.starts_with("./") || path.starts_with(".\\") {
        &path[2..]
    } else {
        path
    }
}

fn remove_path_prefix<'a>(mut path: &'a str, mut prefix: &str) -> Option<&'a str> {
    path = remove_dot_slash(path);
    prefix = remove_dot_slash(prefix);

    if prefix == "" {
        return Some(path);
    }

    if prefix.ends_with("/") || prefix.ends_with("\\") {
        prefix = &prefix[..prefix.len() - 1];
    }

    if !path.starts_with(prefix) {
        return None;
    }

    if path.len() <= prefix.len() {
        return None;
    }

    if path.as_bytes()[prefix.len()] == b'/' || path.as_bytes()[prefix.len()] == b'\\' {
        return Some(&path[prefix.len() + 1..]);
    } else {
        return None;
    }
}

#[cfg(test)]
mod test {
    #[test]
    fn remove_path_prefix() {
        assert_eq!(
            Some("abc.proto"),
            super::remove_path_prefix("xxx/abc.proto", "xxx")
        );
        assert_eq!(
            Some("abc.proto"),
            super::remove_path_prefix("xxx/abc.proto", "xxx/")
        );
        assert_eq!(
            Some("abc.proto"),
            super::remove_path_prefix("../xxx/abc.proto", "../xxx/")
        );
        assert_eq!(
            Some("abc.proto"),
            super::remove_path_prefix("abc.proto", ".")
        );
        assert_eq!(
            Some("abc.proto"),
            super::remove_path_prefix("abc.proto", "./")
        );
        assert_eq!(None, super::remove_path_prefix("xxx/abc.proto", "yyy"));
        assert_eq!(None, super::remove_path_prefix("xxx/abc.proto", "yyy/"));
    }
}
<|endoftext|>


<commit_before>use coordinates::{CoordinateSystem, Point};
use std::ops::{Index, IndexMut};
use std::ops::{Add, Sub, Mul, Div, Deref, DerefMut};
use typenum::uint::Unsigned;
use typenum::Pow;
use generic_array::{GenericArray, ArrayLength};
use super::{CovariantIndex, ContravariantIndex, Variance, IndexType};

/// This is a struct that represents a generic tensor
pub struct Tensor<T: CoordinateSystem, U: Variance>
    where T::Dimension: Pow<U::Rank>,
          <T::Dimension as Pow<U::Rank>>::Output: ArrayLength<f64>
{
    p: Point<T>,
    x: GenericArray<f64, <T::Dimension as Pow<U::Rank>>::Output>
}

impl<T, U> Clone for Tensor<T, U>
    where T: CoordinateSystem,
          U: Variance,
          T::Dimension: Pow<U::Rank>,
          <T::Dimension as Pow<U::Rank>>::Output: ArrayLength<f64>
{
    fn clone(&self) -> Tensor<T, U> {
        Tensor {
            p: self.p.clone(),
            x: self.x.clone()
        }
    }
}

impl<T, U> Copy for Tensor<T, U>
    where T: CoordinateSystem,
          U: Variance,
          T::Dimension: Pow<U::Rank>,
          <T::Dimension as ArrayLength<f64>>::ArrayType: Copy,
          <T::Dimension as Pow<U::Rank>>::Output: ArrayLength<f64>,
          <<T::Dimension as Pow<U::Rank>>::Output as ArrayLength<f64>>::ArrayType: Copy
{}

impl<T, U> Tensor<T, U>
    where T: CoordinateSystem,
          U: Variance,
          T::Dimension: Pow<U::Rank>,
          <T::Dimension as Pow<U::Rank>>::Output: ArrayLength<f64>
{
    /// Returns the point at which the tensor is defined.
    pub fn get_point(&self) -> &Point<T> {
        &self.p
    }

    /// Converts a set of tensor indices passed as a slice into a single index for the internal array.
    /// The length of the slice (the number of indices) has to be compatible with the rank of the tensor.
    pub fn get_coord(i: &[usize]) -> usize {
        assert_eq!(i.len(), U::rank());
        let dim = T::dimension();
        let index = i.into_iter().fold(0, |res, idx| {
            assert!(*idx < dim);
            res * dim + idx
        });
        index
    }

    /// Returns the variance of the tensor, that is, the list of the index types.
    /// A vector would return vec![Contravariant], a metric tensor: vec![Covariant, Covariant].
    pub fn get_variance() -> Vec<IndexType> {
        U::variance()
    }

    /// Returns the rank of the tensor
    pub fn get_rank() -> usize {
        U::rank()
    }

    /// Returns the number of coordinates of the tensor
    pub fn get_num_coords() -> usize {
        <T::Dimension as Pow<U::Rank>>::Output::to_usize()
    }

    pub fn new(point: Point<T>) -> Tensor<T, U> {
        Tensor {
            p: point,
            x: GenericArray::new()
        }
    }
}

impl<'a, T, U> Index<&'a [usize]> for Tensor<T, U>
    where T: CoordinateSystem,
          U: Variance,
          T::Dimension: Pow<U::Rank>,
          <T::Dimension as Pow<U::Rank>>::Output: ArrayLength<f64>
{
    type Output = f64;

    fn index(&self, idx: &'a [usize]) -> &f64 {
        &self.x[Self::get_coord(idx)]
    }
}

impl<'a, T, U> IndexMut<&'a [usize]> for Tensor<T, U>
    where T: CoordinateSystem,
          U: Variance,
          T::Dimension: Pow<U::Rank>,
          <T::Dimension as Pow<U::Rank>>::Output: ArrayLength<f64>
{
    fn index_mut(&mut self, idx: &'a [usize]) -> &mut f64 {
        &mut self.x[Self::get_coord(idx)]
    }
}

impl<'a, T, U> Index<usize> for Tensor<T, U>
    where T: CoordinateSystem,
          U: Variance,
          T::Dimension: Pow<U::Rank>,
          <T::Dimension as Pow<U::Rank>>::Output: ArrayLength<f64>
{
    type Output = f64;

    fn index(&self, idx: usize) -> &f64 {
        &self.x[idx]
    }
}

impl<'a, T, U> IndexMut<usize> for Tensor<T, U>
    where T: CoordinateSystem,
          U: Variance,
          T::Dimension: Pow<U::Rank>,
          <T::Dimension as Pow<U::Rank>>::Output: ArrayLength<f64>
{
    fn index_mut(&mut self, idx: usize) -> &mut f64 {
        &mut self.x[idx]
    }
}

pub type Scalar<T> = Tensor<T, ()>;
pub type Vector<T> = Tensor<T, ContravariantIndex>;
pub type Covector<T> = Tensor<T, CovariantIndex>;
pub type Matrix<T> = Tensor<T, (ContravariantIndex, CovariantIndex)>;

impl<T: CoordinateSystem> Deref for Scalar<T> {
    type Target = f64;

    fn deref(&self) -> &f64 {
        &self.x[0]
    }
}

impl<T: CoordinateSystem> DerefMut for Scalar<T> {
    fn deref_mut(&mut self) -> &mut f64 {
        &mut self.x[0]
    }
}

// Arithmetic operations

impl<T, U> Add<Tensor<T, U>> for Tensor<T, U>
    where T: CoordinateSystem,
          U: Variance,
          T::Dimension: Pow<U::Rank>,
          <T::Dimension as Pow<U::Rank>>::Output: ArrayLength<f64>
{
    type Output = Tensor<T, U>;

    fn add(mut self, rhs: Tensor<T, U>) -> Tensor<T, U> {
        assert!(self.p == rhs.p);
        for i in 0..(Tensor::<T, U>::get_num_coords()) {
            self[i] = self[i] + rhs[i];
        }
        self
    }
}

impl<T, U> Sub<Tensor<T, U>> for Tensor<T, U>
    where T: CoordinateSystem,
          U: Variance,
          T::Dimension: Pow<U::Rank>,
          <T::Dimension as Pow<U::Rank>>::Output: ArrayLength<f64>
{
    type Output = Tensor<T, U>;

    fn sub(mut self, rhs: Tensor<T, U>) -> Tensor<T, U> {
        assert!(self.p == rhs.p);
        for i in 0..(Tensor::<T, U>::get_num_coords()) {
            self[i] = self[i] - rhs[i];
        }
        self
    }
}

impl<T, U> Mul<f64> for Tensor<T, U>
    where T: CoordinateSystem,
          U: Variance,
          T::Dimension: Pow<U::Rank>,
          <T::Dimension as Pow<U::Rank>>::Output: ArrayLength<f64>
{
    type Output = Tensor<T, U>;

    fn mul(mut self, rhs: f64) -> Tensor<T, U> {
        for i in 0..(Tensor::<T, U>::get_num_coords()) {
            self[i] = self[i] * rhs;
        }
        self
    }
}

impl<T, U> Div<f64> for Tensor<T, U>
    where T: CoordinateSystem,
          U: Variance,
          T::Dimension: Pow<U::Rank>,
          <T::Dimension as Pow<U::Rank>>::Output: ArrayLength<f64>
{
    type Output = Tensor<T, U>;

    fn div(mut self, rhs: f64) -> Tensor<T, U> {
        for i in 0..(Tensor::<T, U>::get_num_coords()) {
            self[i] = self[i] / rhs;
        }
        self
    }
}
<commit_msg>Implemented f64*Tensor<commit_after>use coordinates::{CoordinateSystem, Point};
use std::ops::{Index, IndexMut};
use std::ops::{Add, Sub, Mul, Div, Deref, DerefMut};
use typenum::uint::Unsigned;
use typenum::Pow;
use generic_array::{GenericArray, ArrayLength};
use super::{CovariantIndex, ContravariantIndex, Variance, IndexType};

/// This is a struct that represents a generic tensor
pub struct Tensor<T: CoordinateSystem, U: Variance>
    where T::Dimension: Pow<U::Rank>,
          <T::Dimension as Pow<U::Rank>>::Output: ArrayLength<f64>
{
    p: Point<T>,
    x: GenericArray<f64, <T::Dimension as Pow<U::Rank>>::Output>
}

impl<T, U> Clone for Tensor<T, U>
    where T: CoordinateSystem,
          U: Variance,
          T::Dimension: Pow<U::Rank>,
          <T::Dimension as Pow<U::Rank>>::Output: ArrayLength<f64>
{
    fn clone(&self) -> Tensor<T, U> {
        Tensor {
            p: self.p.clone(),
            x: self.x.clone()
        }
    }
}

impl<T, U> Copy for Tensor<T, U>
    where T: CoordinateSystem,
          U: Variance,
          T::Dimension: Pow<U::Rank>,
          <T::Dimension as ArrayLength<f64>>::ArrayType: Copy,
          <T::Dimension as Pow<U::Rank>>::Output: ArrayLength<f64>,
          <<T::Dimension as Pow<U::Rank>>::Output as ArrayLength<f64>>::ArrayType: Copy
{}

impl<T, U> Tensor<T, U>
    where T: CoordinateSystem,
          U: Variance,
          T::Dimension: Pow<U::Rank>,
          <T::Dimension as Pow<U::Rank>>::Output: ArrayLength<f64>
{
    /// Returns the point at which the tensor is defined.
    pub fn get_point(&self) -> &Point<T> {
        &self.p
    }

    /// Converts a set of tensor indices passed as a slice into a single index for the internal array.
    /// The length of the slice (the number of indices) has to be compatible with the rank of the tensor.
    pub fn get_coord(i: &[usize]) -> usize {
        assert_eq!(i.len(), U::rank());
        let dim = T::dimension();
        let index = i.into_iter().fold(0, |res, idx| {
            assert!(*idx < dim);
            res * dim + idx
        });
        index
    }

    /// Returns the variance of the tensor, that is, the list of the index types.
    /// A vector would return vec![Contravariant], a metric tensor: vec![Covariant, Covariant].
    pub fn get_variance() -> Vec<IndexType> {
        U::variance()
    }

    /// Returns the rank of the tensor
    pub fn get_rank() -> usize {
        U::rank()
    }

    /// Returns the number of coordinates of the tensor
    pub fn get_num_coords() -> usize {
        <T::Dimension as Pow<U::Rank>>::Output::to_usize()
    }

    pub fn new(point: Point<T>) -> Tensor<T, U> {
        Tensor {
            p: point,
            x: GenericArray::new()
        }
    }
}

impl<'a, T, U> Index<&'a [usize]> for Tensor<T, U>
    where T: CoordinateSystem,
          U: Variance,
          T::Dimension: Pow<U::Rank>,
          <T::Dimension as Pow<U::Rank>>::Output: ArrayLength<f64>
{
    type Output = f64;

    fn index(&self, idx: &'a [usize]) -> &f64 {
        &self.x[Self::get_coord(idx)]
    }
}

impl<'a, T, U> IndexMut<&'a [usize]> for Tensor<T, U>
    where T: CoordinateSystem,
          U: Variance,
          T::Dimension: Pow<U::Rank>,
          <T::Dimension as Pow<U::Rank>>::Output: ArrayLength<f64>
{
    fn index_mut(&mut self, idx: &'a [usize]) -> &mut f64 {
        &mut self.x[Self::get_coord(idx)]
    }
}

impl<'a, T, U> Index<usize> for Tensor<T, U>
    where T: CoordinateSystem,
          U: Variance,
          T::Dimension: Pow<U::Rank>,
          <T::Dimension as Pow<U::Rank>>::Output: ArrayLength<f64>
{
    type Output = f64;

    fn index(&self, idx: usize) -> &f64 {
        &self.x[idx]
    }
}

impl<'a, T, U> IndexMut<usize> for Tensor<T, U>
    where T: CoordinateSystem,
          U: Variance,
          T::Dimension: Pow<U::Rank>,
          <T::Dimension as Pow<U::Rank>>::Output: ArrayLength<f64>
{
    fn index_mut(&mut self, idx: usize) -> &mut f64 {
        &mut self.x[idx]
    }
}

pub type Scalar<T> = Tensor<T, ()>;
pub type Vector<T> = Tensor<T, ContravariantIndex>;
pub type Covector<T> = Tensor<T, CovariantIndex>;
pub type Matrix<T> = Tensor<T, (ContravariantIndex, CovariantIndex)>;

impl<T: CoordinateSystem> Deref for Scalar<T> {
    type Target = f64;

    fn deref(&self) -> &f64 {
        &self.x[0]
    }
}

impl<T: CoordinateSystem> DerefMut for Scalar<T> {
    fn deref_mut(&mut self) -> &mut f64 {
        &mut self.x[0]
    }
}

// Arithmetic operations

impl<T, U> Add<Tensor<T, U>> for Tensor<T, U>
    where T: CoordinateSystem,
          U: Variance,
          T::Dimension: Pow<U::Rank>,
          <T::Dimension as Pow<U::Rank>>::Output: ArrayLength<f64>
{
    type Output = Tensor<T, U>;

    fn add(mut self, rhs: Tensor<T, U>) -> Tensor<T, U> {
        assert!(self.p == rhs.p);
        for i in 0..(Tensor::<T, U>::get_num_coords()) {
            self[i] = self[i] + rhs[i];
        }
        self
    }
}

impl<T, U> Sub<Tensor<T, U>> for Tensor<T, U>
    where T: CoordinateSystem,
          U: Variance,
          T::Dimension: Pow<U::Rank>,
          <T::Dimension as Pow<U::Rank>>::Output: ArrayLength<f64>
{
    type Output = Tensor<T, U>;

    fn sub(mut self, rhs: Tensor<T, U>) -> Tensor<T, U> {
        assert!(self.p == rhs.p);
        for i in 0..(Tensor::<T, U>::get_num_coords()) {
            self[i] = self[i] - rhs[i];
        }
        self
    }
}

impl<T, U> Mul<f64> for Tensor<T, U>
    where T: CoordinateSystem,
          U: Variance,
          T::Dimension: Pow<U::Rank>,
          <T::Dimension as Pow<U::Rank>>::Output: ArrayLength<f64>
{
    type Output = Tensor<T, U>;

    fn mul(mut self, rhs: f64) -> Tensor<T, U> {
        for i in 0..(Tensor::<T, U>::get_num_coords()) {
            self[i] = self[i] * rhs;
        }
        self
    }
}

impl<T, U> Mul<Tensor<T, U>> for f64
    where T: CoordinateSystem,
          U: Variance,
          T::Dimension: Pow<U::Rank>,
          <T::Dimension as Pow<U::Rank>>::Output: ArrayLength<f64>
{
    type Output = Tensor<T, U>;

    fn mul(self, mut rhs: Tensor<T, U>) -> Tensor<T, U> {
        for i in 0..(Tensor::<T, U>::get_num_coords()) {
            rhs[i] = rhs[i] * self;
        }
        rhs
    }
}

impl<T, U> Div<f64> for Tensor<T, U>
    where T: CoordinateSystem,
          U: Variance,
          T::Dimension: Pow<U::Rank>,
          <T::Dimension as Pow<U::Rank>>::Output: ArrayLength<f64>
{
    type Output = Tensor<T, U>;

    fn div(mut self, rhs: f64) -> Tensor<T, U> {
        for i in 0..(Tensor::<T, U>::get_num_coords()) {
            self[i] = self[i] / rhs;
        }
        self
    }
}
<|endoftext|>


<commit_before>use std::ops::{Add, AddAssign, Sub, SubAssign};

use str_utils::{count_chars, count_line_breaks};
use tree::Count;

#[derive(Debug, Copy, Clone, PartialEq)]
pub struct TextInfo {
    pub(crate) bytes: Count,
    pub(crate) chars: Count,
    pub(crate) line_breaks: Count,
}

impl TextInfo {
    pub fn new() -> TextInfo {
        TextInfo {
            bytes: 0,
            chars: 0,
            line_breaks: 0,
        }
    }

    #[inline]
    #[inline]
    pub fn from_str(text: &str) -> TextInfo {
        TextInfo {
            bytes: text.len() as Count,
            chars: count_chars(text) as Count,
            line_breaks: count_line_breaks(text) as Count,
        }
    }
}

impl Add for TextInfo {
    type Output = Self;
    #[inline]
    fn add(self, rhs: TextInfo) -> TextInfo {
        TextInfo {
            bytes: self.bytes + rhs.bytes,
            chars: self.chars + rhs.chars,
            line_breaks: self.line_breaks + rhs.line_breaks,
        }
    }
}

impl AddAssign for TextInfo {
    #[inline]
    fn add_assign(&mut self, other: TextInfo) {
        *self = *self + other;
    }
}

impl Sub for TextInfo {
    type Output = Self;
    #[inline]
    fn sub(self, rhs: TextInfo) -> TextInfo {
        TextInfo {
            bytes: self.bytes - rhs.bytes,
            chars: self.chars - rhs.chars,
            line_breaks: self.line_breaks - rhs.line_breaks,
        }
    }
}

impl SubAssign for TextInfo {
    #[inline]
    fn sub_assign(&mut self, other: TextInfo) {
        *self = *self - other;
    }
}
<commit_msg>Silly mistake in where I put the inline attribute.<commit_after>use std::ops::{Add, AddAssign, Sub, SubAssign};

use str_utils::{count_chars, count_line_breaks};
use tree::Count;

#[derive(Debug, Copy, Clone, PartialEq)]
pub struct TextInfo {
    pub(crate) bytes: Count,
    pub(crate) chars: Count,
    pub(crate) line_breaks: Count,
}

impl TextInfo {
    #[inline]
    pub fn new() -> TextInfo {
        TextInfo {
            bytes: 0,
            chars: 0,
            line_breaks: 0,
        }
    }

    #[inline]
    pub fn from_str(text: &str) -> TextInfo {
        TextInfo {
            bytes: text.len() as Count,
            chars: count_chars(text) as Count,
            line_breaks: count_line_breaks(text) as Count,
        }
    }
}

impl Add for TextInfo {
    type Output = Self;
    #[inline]
    fn add(self, rhs: TextInfo) -> TextInfo {
        TextInfo {
            bytes: self.bytes + rhs.bytes,
            chars: self.chars + rhs.chars,
            line_breaks: self.line_breaks + rhs.line_breaks,
        }
    }
}

impl AddAssign for TextInfo {
    #[inline]
    fn add_assign(&mut self, other: TextInfo) {
        *self = *self + other;
    }
}

impl Sub for TextInfo {
    type Output = Self;
    #[inline]
    fn sub(self, rhs: TextInfo) -> TextInfo {
        TextInfo {
            bytes: self.bytes - rhs.bytes,
            chars: self.chars - rhs.chars,
            line_breaks: self.line_breaks - rhs.line_breaks,
        }
    }
}

impl SubAssign for TextInfo {
    #[inline]
    fn sub_assign(&mut self, other: TextInfo) {
        *self = *self - other;
    }
}
<|endoftext|>