<commit_before>//! Convert from and to internal representation (`SSAStorage`)
//!
//! This module provides all the support needed to convert the internal
//! representation of radeco IR
//! into human readable text format and to parse the same back to radeco IR.
//! The text based
//! representation is inspired from (and probably similar) LLVM IR.

use std::collections::HashMap;
use std::default;
use petgraph::graph::NodeIndex;
use middle::ir::{MOpcode};
use middle::ssa::ssastorage::{NodeData, SSAStorage};
use middle::ssa::ssa_traits::{SSA, SSAWalk, ValueType};
use middle::ssa::cfg_traits::CFG;

const BLOCK_SEP: &'static str = "{";
const CL_BLOCK_SEP: &'static str = "}";

#[macro_export]
macro_rules! ir_write {
    ($n: expr, $ssa: expr) => ({
        {
            use $crate::middle::ir_writer::IRWriter;

            let mut writer = IRWriter::default();
            writer.emit_il($n, $ssa, &mut io::stdout());
        }
    });
    ($n: expr, $ssa: expr, $f: expr) => ({
        {
            use $crate::middle::ir_writer::IRWriter;
            use std::fs::File;
            use std::io::prelude::*;

            let mut writer = IRWriter::default();
            let mut f = File::create($f).expect("Unable to create file");
            writer.emit_il($n, $ssa, &mut f);
        }
    });
}

macro_rules! concat_str {
    ($s:expr, $t:expr) => { $s = format!("{}{}", $s, $t); }
}

macro_rules! concat_strln {
    ($s:expr, $t:expr) => { $s = format!("{}\n{}", $s, $t); }
}

// Format constants.
macro_rules! fmt_const {
    ($c:expr) => { format!("#x{:x}", $c); }
}

// Format bb.
macro_rules! bb {
    ($bb:expr) => { format!("bb_{}():", $bb); }
}

// Format an expression
macro_rules! expr {
    ($r:expr, $tp:tt = $rhs:expr) => { format!("%{}{} = {}", $r, fmttyp!($tp), $rhs); }
}

// Format a type
macro_rules! fmttyp {
    ($t: expr) => { format!(":${}", $t); }
}

macro_rules! fmt_fn {
    ($f:expr) => { format!("define-fun {}(unknown) -> unknown {}", $f, BLOCK_SEP); }
}

macro_rules! fmtarg {
    ($v:expr, $typ:expr) => { format!("%{}{}", $v, fmttyp!($typ)); }
}

macro_rules! indent {
    ($n:expr, $s:expr) => { format!("{}{}", IRWriter::fmt_indent($n), $s); }
}

// TODO before implementing this. This will also help in writing the pseudo C
// output.
// 1. Associate nodes and addresses. Currently, addresses are not stored with
// the nodes. This is
// trivial to implement as the phiplacer has the requisite information and
// this can be
//    associated in finish_block.
// 2. Write an iterator for SSAStorage that yeilds nodes "inorder" i.e. ordered
// by their
//    corresponding instruction addresses in the original binary.
// 3. Add a pass to load symbols and flags from radare2. This will produce more
// readable output in
//    both the cases.

#[derive(Clone, Debug)]
pub struct IRWriter {
    seen: HashMap<NodeIndex, u64>,
    indent: u64,
    ctr: u64,
}

impl default::Default for IRWriter {
    fn default() -> IRWriter {
        IRWriter {
            seen: HashMap::new(),
            indent: 1,
            ctr: 0,
        }
    }
}

impl IRWriter {
    pub fn parse<T: AsRef<str>>(_il: T) -> SSAStorage {
        unimplemented!();
    }

    fn fmt_operands(&mut self, operands: &[NodeIndex], ssa: &SSAStorage) -> Vec<String> {
        let mut result = Vec::new();
        for operand in operands {
            match ssa.g[*operand] {
                NodeData::BasicBlock(addr) => result.push(format!("{}", addr)),
                NodeData::DynamicAction => result.push("dynamic_action".to_owned()),
                NodeData::Op(MOpcode::OpConst(ref value), _) => result.push(fmt_const!(value)),
                NodeData::Comment(_, ref named) => result.push(named.clone()),
                _ => {
                    let next = self.ctr + 1;
                    let op_i = self.seen.entry(*operand).or_insert(next);
                    if *op_i == next {
                        self.ctr += 1;
                    }
                    result.push(format!("%{}", op_i));
                }
            }
        }
        result
    }

    fn fmt_expression(&mut self,
                      ni: NodeIndex,
                      opcode: MOpcode,
                      vt: ValueType,
                      operands: Vec<String>,
                      ssa: &SSAStorage)
                      -> String {
        let next = self.ctr + 1;
        let result_idx = self.seen.entry(ni).or_insert(next);
        if *result_idx == next {
            self.ctr += 1;
        }

        let w = match vt {
            ValueType::Integer { width } => width,
        };

        match opcode {
            MOpcode::OpAdd => format!("%{}: $Unknown{}  = {} + {}",
                                      result_idx,
                                      w,
                                      operands[0],
                                      operands[1]),
            MOpcode::OpSub => format!("%{}: $Unknown{} = {} - {}",
                                      result_idx,
                                      w,
                                      operands[0],
                                      operands[1]),
            MOpcode::OpMul => format!("%{}: $Unknown{} = {} * {}",
                                      result_idx,
                                      w,
                                      operands[0],
                                      operands[1]),
            MOpcode::OpDiv => format!("%{}: $Unknown{} = {} / {}",
                                      result_idx,
                                      w,
                                      operands[0],
                                      operands[1]),
            MOpcode::OpMod => format!("%{}: $Unknown{} = {} % {}",
                                      result_idx,
                                      w,
                                      operands[0],
                                      operands[1]),
            MOpcode::OpAnd => format!("%{}: $Unknown{} = {} & {}",
                                      result_idx,
                                      w,
                                      operands[0],
                                      operands[1]),
            MOpcode::OpOr => format!("%{}: $Unknown{} = {} | {}",
                                     result_idx,
                                     w,
                                     operands[0],
                                     operands[1]),
            MOpcode::OpXor => format!("%{}: $Unknown{} = {} ^ {}",
                                      result_idx,
                                      w,
                                      operands[0],
                                      operands[1]),
            MOpcode::OpNot => format!("%{}: $Unknown{} = !{}", result_idx, w, operands[0]),
            MOpcode::OpCmp => format!("%{}: $Unknown{} = {} == {}",
                                      result_idx,
                                      w,
                                      operands[0],
                                      operands[1]),
            MOpcode::OpGt => format!("%{}: $Unknown{} = {} > {}",
                                     result_idx,
                                     w,
                                     operands[0],
                                     operands[1]),
            MOpcode::OpLt => format!("%{}: $Unknown{} = {} < {}",
                                     result_idx,
                                     w,
                                     operands[0],
                                     operands[1]),
            MOpcode::OpLsl => format!("%{}: $Unknown{} = {} << {}",
                                      result_idx,
                                      w,
                                      operands[0],
                                      operands[1]),
            MOpcode::OpLsr => format!("%{}: $Unknown{} = {} >> {}",
                                      result_idx,
                                      w,
                                      operands[0],
                                      operands[1]),
            MOpcode::OpLoad => format!("%{}: $Unknown{} = Load({}, {})",
                                       result_idx,
                                       w,
                                       operands[0],
                                       operands[1]),
            MOpcode::OpStore => format!("%{}: $Unknown{} = Store({}, {}, {})",
                                        result_idx,
                                        w,
                                        operands[0],
                                        operands[1],
                                        operands[2]),
            MOpcode::OpNarrow(wd) => format!("%{}: $Unknown{} = Narrow{}({})",
                                             result_idx,
                                             w,
                                             wd,
                                             operands[0]),
            MOpcode::OpWiden(wd) => format!("%{}: $Unknown{} = Widen{}({})",
                                            result_idx,
                                            w,
                                            wd,
                                            operands[0]),
            MOpcode::OpCall => {
                let mem = "mem".to_owned();
                format!("CALL {}({})",
                        operands[0],
                        &operands[1..]
                             .iter()
                             .enumerate()
                             .map(|i| format!("{}={}", ssa.regnames.get(i.0).unwrap_or(&mem), i.1))
                             .fold(String::new(), |acc, x| {
                                 if !acc.is_empty() {
                                     format!("{}, {}", acc, x)
                                 } else {
                                     x
                                 }
                             }))
            }
            _ => unreachable!(),
        }
    }

    fn fmt_indent(by: u64) -> String {
        let mut indent = String::new();
        for _ in 0..by {
            indent.push_str("    ");
        }
        indent
    }

    pub fn emit_il(&mut self, fn_name: Option<String>, ssa: &SSAStorage) -> String
    {
        let mut last = None;
        let mut text_il = String::new();
        let fn_name = if fn_name.is_some() {
            fn_name.unwrap()
        } else {
            "fn_apple".to_owned()
        };

        for node in ssa.inorder_walk() {
            let line = match ssa.g[node] {
                NodeData::Op(opcode, vt) => {
                    if let MOpcode::OpConst(_) = opcode {
                        String::new()
                    } else {
                        let operands = self.fmt_operands(ssa.get_operands(&node).as_slice(), ssa);
                        indent!(self.indent,
                                self.fmt_expression(node, opcode, vt, operands, &ssa))
                    }
                }
                NodeData::Phi(_, _) => {
                    let operands = self.fmt_operands(ssa.get_operands(&node).as_slice(), ssa);
                    let next = self.ctr + 1;
                    let result_idx = self.seen.entry(node).or_insert(next);
                    if *result_idx == next {
                        self.ctr += 1;
                    }
                    let mut phi_line = format!("%{} = Phi(", result_idx);
                    for operand in operands {
                        phi_line = format!("{}{}, ", phi_line, operand);
                    }
                    let len = phi_line.len();
                    phi_line.truncate(len - 2);
                    phi_line.push_str(")");
                    indent!(self.indent, phi_line)
                }
                NodeData::Undefined(_) => {
                    "Undefined".to_owned()
                }
                NodeData::BasicBlock(addr) => {
                    let bbline = if let Some(ref prev_block) = last {
                        let mut jmp_statement = "JMP".to_owned();
                        let outgoing = ssa.edges_of(prev_block)
                                          .iter()
                                          .map(|x| (ssa.target_of(&x.0), x.1))
                                          .collect::<Vec<_>>();
                        // This is a conditional jump.
                        if outgoing.len() > 1 {
                            let condition = self.fmt_operands(&[ssa.selector_of(prev_block)
                                                                   .unwrap()],
                                                              ssa);
                            jmp_statement = format!("{} IF {}", jmp_statement, condition[0]);
                        }

                        let mut target_string = String::new();
                        for (target, edge_type) in outgoing {
                            if target == node && (edge_type == 0 || edge_type == 2) {
                                continue;
                            }

                            let join = if edge_type == 0 {
                                " ELSE "
                            } else {
                                " "
                            };

                            target_string = format!("{}{}{}",
                                                    target_string,
                                                    join,
                                                    self.fmt_operands(&[target], &ssa)[0]);
                        }

                        if target_string.is_empty() {
                            indent!(self.indent - 1, bb!(addr))
                        } else {
                            concat_str!(jmp_statement, target_string);
                            concat_strln!(text_il, indent!(self.indent, jmp_statement));
                            indent!(self.indent - 1, bb!(addr))
                        }
                    } else {
                        self.indent += 1;
                        fmt_fn!(fn_name)
                    };
                    last = Some(node);
                    bbline
                }
                _ => {
                    String::new()
                }
            };

            if !line.is_empty() {
                concat_strln!(text_il, line);
            }
        }

        let exit_node = ssa.exit_node();
        let final_state = ssa.registers_at(&exit_node);
        let mem_comment = "mem".to_owned();

        for (i, reg) in ssa.get_operands(&final_state).iter().enumerate() {
            let reg_assign = match ssa.g[*reg] {
                NodeData::Comment(_, _) => String::new(),
                _ => {
                    format!("{} = {}",
                            ssa.regnames.get(i).unwrap_or_else(|| {
                                assert_eq!(i, ssa.regnames.len());
                                &mem_comment
                            }),
                            self.fmt_operands(&[*reg], &ssa)[0])
                }
            };
            if !reg_assign.is_empty() {
                concat_strln!(text_il, indent!(self.indent, reg_assign));
            }
        }

        concat_strln!(text_il, CL_BLOCK_SEP);
        text_il
    }
}
<commit_msg>check for selector before accessing it<commit_after>//! Convert from and to internal representation (`SSAStorage`)
//!
//! This module provides all the support needed to convert the internal
//! representation of radeco IR
//! into human readable text format and to parse the same back to radeco IR.
//! The text based
//! representation is inspired from (and probably similar) LLVM IR.

use std::collections::HashMap;
use std::default;
use petgraph::graph::NodeIndex;
use middle::ir::{MOpcode};
use middle::ssa::ssastorage::{NodeData, SSAStorage};
use middle::ssa::ssa_traits::{SSA, SSAWalk, ValueType};
use middle::ssa::cfg_traits::CFG;

const BLOCK_SEP: &'static str = "{";
const CL_BLOCK_SEP: &'static str = "}";

#[macro_export]
macro_rules! ir_write {
    ($n: expr, $ssa: expr) => ({
        {
            use $crate::middle::ir_writer::IRWriter;

            let mut writer = IRWriter::default();
            writer.emit_il($n, $ssa, &mut io::stdout());
        }
    });
    ($n: expr, $ssa: expr, $f: expr) => ({
        {
            use $crate::middle::ir_writer::IRWriter;
            use std::fs::File;
            use std::io::prelude::*;

            let mut writer = IRWriter::default();
            let mut f = File::create($f).expect("Unable to create file");
            writer.emit_il($n, $ssa, &mut f);
        }
    });
}

macro_rules! concat_str {
    ($s:expr, $t:expr) => { $s = format!("{}{}", $s, $t); }
}

macro_rules! concat_strln {
    ($s:expr, $t:expr) => { $s = format!("{}\n{}", $s, $t); }
}

// Format constants.
macro_rules! fmt_const {
    ($c:expr) => { format!("#x{:x}", $c); }
}

// Format bb.
macro_rules! bb {
    ($bb:expr) => { format!("bb_{}():", $bb); }
}

// Format an expression
macro_rules! expr {
    ($r:expr, $tp:tt = $rhs:expr) => { format!("%{}{} = {}", $r, fmttyp!($tp), $rhs); }
}

// Format a type
macro_rules! fmttyp {
    ($t: expr) => { format!(":${}", $t); }
}

macro_rules! fmt_fn {
    ($f:expr) => { format!("define-fun {}(unknown) -> unknown {}", $f, BLOCK_SEP); }
}

macro_rules! fmtarg {
    ($v:expr, $typ:expr) => { format!("%{}{}", $v, fmttyp!($typ)); }
}

macro_rules! indent {
    ($n:expr, $s:expr) => { format!("{}{}", IRWriter::fmt_indent($n), $s); }
}

// TODO before implementing this. This will also help in writing the pseudo C
// output.
// 1. Associate nodes and addresses. Currently, addresses are not stored with
// the nodes. This is
// trivial to implement as the phiplacer has the requisite information and
// this can be
//    associated in finish_block.
// 2. Write an iterator for SSAStorage that yeilds nodes "inorder" i.e. ordered
// by their
//    corresponding instruction addresses in the original binary.
// 3. Add a pass to load symbols and flags from radare2. This will produce more
// readable output in
//    both the cases.

#[derive(Clone, Debug)]
pub struct IRWriter {
    seen: HashMap<NodeIndex, u64>,
    indent: u64,
    ctr: u64,
}

impl default::Default for IRWriter {
    fn default() -> IRWriter {
        IRWriter {
            seen: HashMap::new(),
            indent: 1,
            ctr: 0,
        }
    }
}

impl IRWriter {
    pub fn parse<T: AsRef<str>>(_il: T) -> SSAStorage {
        unimplemented!();
    }

    fn fmt_operands(&mut self, operands: &[NodeIndex], ssa: &SSAStorage) -> Vec<String> {
        let mut result = Vec::new();
        for operand in operands {
            match ssa.g[*operand] {
                NodeData::BasicBlock(addr) => result.push(format!("{}", addr)),
                NodeData::DynamicAction => result.push("dynamic_action".to_owned()),
                NodeData::Op(MOpcode::OpConst(ref value), _) => result.push(fmt_const!(value)),
                NodeData::Comment(_, ref named) => result.push(named.clone()),
                _ => {
                    let next = self.ctr + 1;
                    let op_i = self.seen.entry(*operand).or_insert(next);
                    if *op_i == next {
                        self.ctr += 1;
                    }
                    result.push(format!("%{}", op_i));
                }
            }
        }
        result
    }

    fn fmt_expression(&mut self,
                      ni: NodeIndex,
                      opcode: MOpcode,
                      vt: ValueType,
                      operands: Vec<String>,
                      ssa: &SSAStorage)
                      -> String {
        let next = self.ctr + 1;
        let result_idx = self.seen.entry(ni).or_insert(next);
        if *result_idx == next {
            self.ctr += 1;
        }

        let w = match vt {
            ValueType::Integer { width } => width,
        };

        match opcode {
            MOpcode::OpAdd => format!("%{}: $Unknown{}  = {} + {}",
                                      result_idx,
                                      w,
                                      operands[0],
                                      operands[1]),
            MOpcode::OpSub => format!("%{}: $Unknown{} = {} - {}",
                                      result_idx,
                                      w,
                                      operands[0],
                                      operands[1]),
            MOpcode::OpMul => format!("%{}: $Unknown{} = {} * {}",
                                      result_idx,
                                      w,
                                      operands[0],
                                      operands[1]),
            MOpcode::OpDiv => format!("%{}: $Unknown{} = {} / {}",
                                      result_idx,
                                      w,
                                      operands[0],
                                      operands[1]),
            MOpcode::OpMod => format!("%{}: $Unknown{} = {} % {}",
                                      result_idx,
                                      w,
                                      operands[0],
                                      operands[1]),
            MOpcode::OpAnd => format!("%{}: $Unknown{} = {} & {}",
                                      result_idx,
                                      w,
                                      operands[0],
                                      operands[1]),
            MOpcode::OpOr => format!("%{}: $Unknown{} = {} | {}",
                                     result_idx,
                                     w,
                                     operands[0],
                                     operands[1]),
            MOpcode::OpXor => format!("%{}: $Unknown{} = {} ^ {}",
                                      result_idx,
                                      w,
                                      operands[0],
                                      operands[1]),
            MOpcode::OpNot => format!("%{}: $Unknown{} = !{}", result_idx, w, operands[0]),
            MOpcode::OpCmp => format!("%{}: $Unknown{} = {} == {}",
                                      result_idx,
                                      w,
                                      operands[0],
                                      operands[1]),
            MOpcode::OpGt => format!("%{}: $Unknown{} = {} > {}",
                                     result_idx,
                                     w,
                                     operands[0],
                                     operands[1]),
            MOpcode::OpLt => format!("%{}: $Unknown{} = {} < {}",
                                     result_idx,
                                     w,
                                     operands[0],
                                     operands[1]),
            MOpcode::OpLsl => format!("%{}: $Unknown{} = {} << {}",
                                      result_idx,
                                      w,
                                      operands[0],
                                      operands[1]),
            MOpcode::OpLsr => format!("%{}: $Unknown{} = {} >> {}",
                                      result_idx,
                                      w,
                                      operands[0],
                                      operands[1]),
            MOpcode::OpLoad => format!("%{}: $Unknown{} = Load({}, {})",
                                       result_idx,
                                       w,
                                       operands[0],
                                       operands[1]),
            MOpcode::OpStore => format!("%{}: $Unknown{} = Store({}, {}, {})",
                                        result_idx,
                                        w,
                                        operands[0],
                                        operands[1],
                                        operands[2]),
            MOpcode::OpNarrow(wd) => format!("%{}: $Unknown{} = Narrow{}({})",
                                             result_idx,
                                             w,
                                             wd,
                                             operands[0]),
            MOpcode::OpWiden(wd) => format!("%{}: $Unknown{} = Widen{}({})",
                                            result_idx,
                                            w,
                                            wd,
                                            operands[0]),
            MOpcode::OpCall => {
                let mem = "mem".to_owned();
                format!("CALL {}({})",
                        operands[0],
                        &operands[1..]
                             .iter()
                             .enumerate()
                             .map(|i| format!("{}={}", ssa.regnames.get(i.0).unwrap_or(&mem), i.1))
                             .fold(String::new(), |acc, x| {
                                 if !acc.is_empty() {
                                     format!("{}, {}", acc, x)
                                 } else {
                                     x
                                 }
                             }))
            }
            _ => unreachable!(),
        }
    }

    fn fmt_indent(by: u64) -> String {
        let mut indent = String::new();
        for _ in 0..by {
            indent.push_str("    ");
        }
        indent
    }

    pub fn emit_il(&mut self, fn_name: Option<String>, ssa: &SSAStorage) -> String
    {
        let mut last = None;
        let mut text_il = String::new();
        let fn_name = if fn_name.is_some() {
            fn_name.unwrap()
        } else {
            "fn_apple".to_owned()
        };

        for node in ssa.inorder_walk() {
            let line = match ssa.g[node] {
                NodeData::Op(opcode, vt) => {
                    if let MOpcode::OpConst(_) = opcode {
                        String::new()
                    } else {
                        let operands = self.fmt_operands(ssa.get_operands(&node).as_slice(), ssa);
                        indent!(self.indent,
                                self.fmt_expression(node, opcode, vt, operands, &ssa))
                    }
                }
                NodeData::Phi(_, _) => {
                    let operands = self.fmt_operands(ssa.get_operands(&node).as_slice(), ssa);
                    let next = self.ctr + 1;
                    let result_idx = self.seen.entry(node).or_insert(next);
                    if *result_idx == next {
                        self.ctr += 1;
                    }
                    let mut phi_line = format!("%{} = Phi(", result_idx);
                    for operand in operands {
                        phi_line = format!("{}{}, ", phi_line, operand);
                    }
                    let len = phi_line.len();
                    phi_line.truncate(len - 2);
                    phi_line.push_str(")");
                    indent!(self.indent, phi_line)
                }
                NodeData::Undefined(_) => {
                    "Undefined".to_owned()
                }
                NodeData::BasicBlock(addr) => {
                    let bbline = if let Some(ref prev_block) = last {
                        let mut jmp_statement = "JMP".to_owned();
                        let outgoing = ssa.edges_of(prev_block)
                                          .iter()
                                          .map(|x| (ssa.target_of(&x.0), x.1))
                                          .collect::<Vec<_>>();
                        // This is a conditional jump.
                        if ssa.is_selector(&prev_block) && outgoing.len() > 1 {
                            let condition = self.fmt_operands(&[ssa.selector_of(prev_block)
                                                                   .unwrap()],
                                                              ssa);
                            jmp_statement = format!("{} IF {}", jmp_statement, condition[0]);
                        }

                        let mut target_string = String::new();
                        for (target, edge_type) in outgoing {
                            if target == node && (edge_type == 0 || edge_type == 2) {
                                continue;
                            }

                            let join = if edge_type == 0 {
                                " ELSE "
                            } else {
                                " "
                            };

                            target_string = format!("{}{}{}",
                                                    target_string,
                                                    join,
                                                    self.fmt_operands(&[target], &ssa)[0]);
                        }

                        if target_string.is_empty() {
                            indent!(self.indent - 1, bb!(addr))
                        } else {
                            concat_str!(jmp_statement, target_string);
                            concat_strln!(text_il, indent!(self.indent, jmp_statement));
                            indent!(self.indent - 1, bb!(addr))
                        }
                    } else {
                        self.indent += 1;
                        fmt_fn!(fn_name)
                    };
                    last = Some(node);
                    bbline
                }
                _ => {
                    String::new()
                }
            };

            if !line.is_empty() {
                concat_strln!(text_il, line);
            }
        }

        let exit_node = ssa.exit_node();
        let final_state = ssa.registers_at(&exit_node);
        let mem_comment = "mem".to_owned();

        for (i, reg) in ssa.get_operands(&final_state).iter().enumerate() {
            let reg_assign = match ssa.g[*reg] {
                NodeData::Comment(_, _) => String::new(),
                _ => {
                    format!("{} = {}",
                            ssa.regnames.get(i).unwrap_or_else(|| {
                                assert_eq!(i, ssa.regnames.len());
                                &mem_comment
                            }),
                            self.fmt_operands(&[*reg], &ssa)[0])
                }
            };
            if !reg_assign.is_empty() {
                concat_strln!(text_il, indent!(self.indent, reg_assign));
            }
        }

        concat_strln!(text_il, CL_BLOCK_SEP);
        text_il
    }
}
<|endoftext|>


<commit_before>//! Core type for communicating a collection of `D: Data` records.
//!
//! `Message<D>` is meant to be treated as a `Vec<D>`, with the caveat that it may wrap either
//! typed `Vec<D>` data or binary `Vec<u8>` data that have not yet been deserialized. The type
//! implements `Deref` and `DerefMut` with `Target = Vec<D>`, whose implementations accommodate
//! the possibly serialized representation.
use timely_communication::{Serialize, Push};
use std::ops::{Deref, DerefMut};
use abomonation::{Abomonation, encode, decode};

#[derive(Clone)]
pub struct Message<T, D> {
    pub time: T,
    pub data: Content<D>,
    pub from: usize,
    pub seq: usize,
}

impl<T, D> Message<T, D> {
    #[inline]
    pub fn new(time: T, data: Content<D>, from: usize, seq: usize) -> Message<T, D> {
        Message {
            time: time,
            data: data,
            from: from,
            seq: seq,
        }
    }
}

// Implementation required to get different behavior out of communication fabric.
impl<T: Abomonation+Clone, D: Abomonation> Serialize for Message<T, D> {
    #[inline]
    fn into_bytes(&mut self, bytes: &mut Vec<u8>) {
        unsafe { encode(&self.time, bytes); }
        unsafe { encode(&self.from, bytes); }
        unsafe { encode(&self.seq, bytes); }
        let vec: &Vec<D> = self.data.deref();
        unsafe { encode(vec, bytes); }
    }
    #[inline]
    fn from_bytes(bytes: &mut Vec<u8>) -> Self {
        let mut bytes = ::std::mem::replace(bytes, Vec::new());
        let x_len = bytes.len();
        let (time, from, seq, offset) = {
            let (t,r) = unsafe { decode::<T>(&mut bytes) }.unwrap();
            let (&f,r) = unsafe { decode::<usize>(r) }.unwrap();
            let (&s,r) = unsafe { decode::<usize>(r) }.unwrap();
            let o = x_len - r.len();
            ((*t).clone(), f, s, o)
        };

        let length = unsafe { decode::<Vec<D>>(&mut bytes[offset..]) }.unwrap().0.len();
        Message::new(time, Content::Bytes(bytes, offset, length), from, seq)
    }
}

#[derive(Clone)]
pub enum Content<D> {
    Bytes(Vec<u8>, usize, usize),  // bytes[offset..] decodes to length elements
    Typed(Vec<D>),
}

// ALLOC : This Drop implementation gets *very* angry if we drop allocated data.
// ALLOC : It probably shouldn't be used in practice, but should help track down who is being
// ALLOC : bad about respecting allocated memory.
// impl<D> Drop for Message<D> {
//     match self.contents {
//         Content::Bytes(bytes, _, _) => { assert!(bytes.capacity() == 0); }
//         Content::Typed(typed) => { assert!(typed.capacity() == 0); }
//     }
// }

impl<D> Content<D> {
    /// Default number of elements in a typed allocated message. This could vary as a function of
    /// `std::mem::size_of::<D>()`, so is left as a method rather than a constant.
    #[inline]
    pub fn default_length() -> usize { 4096 }

    /// The length of the underlying typed vector.
    ///
    /// The length is tracked without needing to deserialize the data, so that this method can be
    /// called even for `D` that do not implement `Serializable`.
    #[inline]
    pub fn len(&self) -> usize {
        match *self {
            Content::Bytes(_, _, length) => length,
            Content::Typed(ref data) => data.len(),
        }
    }

    /// Constructs a `Message` from typed data, replacing its argument with `Vec::new()`.
    #[inline]
    pub fn from_typed(typed: &mut Vec<D>) -> Content<D> {
        Content::Typed(::std::mem::replace(typed, Vec::new()))
    }

    /// Returns the typed vector, cleared, or a Vec::new() if the data are binary (and drops them
    /// on the floor, I guess! Ouch.
    /// ALLOC : dropping of binary data. likely called only by persons who pushed typed data on,
    /// ALLOC : so perhaps not all that common. Could put a panic! here just for fun! :D
    /// ALLOC : casual dropping of contents of `data`, which might have allocated memory.
    #[inline]
    pub fn into_typed(self) -> Vec<D> {
        match self {
            Content::Bytes(_,_,_) => Vec::new(),
            Content::Typed(mut data) => { data.clear(); data },
        }
    }

    #[inline]
    pub fn push_at<T, P: Push<(T, Content<D>)>>(buffer: &mut Vec<D>, time: T, pusher: &mut P) {

        let data = Content::from_typed(buffer);
        let mut message = Some((time, data));

        pusher.push(&mut message);

        if let Some((_, Content::Typed(mut typed))) = message {
            typed.clear();
            *buffer = typed;
        }
        else {
            *buffer = Vec::with_capacity(Content::<D>::default_length());
        }

        // TODO : Assert failing, but not sure if is bug when deser can make arbitrary lengths
        // TODO : in clone. Revisit!
        // assert!(buffer.capacity() == Content::<D>::default_length());
        if buffer.capacity() != Content::<D>::default_length() {
            *buffer = Vec::with_capacity(Content::<D>::default_length());
        }
    }
}

impl<D: Abomonation> Deref for Content<D> {
    type Target = Vec<D>;
    #[inline]
    fn deref(&self) -> &Vec<D> {
        match *self {
            Content::Bytes(ref bytes, offset, _length) => {
                // verify wasn't actually safe, it turns out...
                unsafe { ::std::mem::transmute(bytes.get_unchecked(offset)) }
            },
            Content::Typed(ref data) => data,
        }
    }
}

// TODO : Rather than .clone() the decoded data, we should try and re-rig serialization so that the
// TODO : underlying byte array can just be handed to Vec::from_raw_parts, cloning any owned data.
// TODO : I think we would need to make sure that the byte array had the right alignment, so that
// TODO : when the Vec is eventually dropped we don't de-allocate the wrong number of bytes.
// TODO : This requires mucking with the Abomonation code, as it doesn't currently let you step in
// TODO : and skip copying the 24 byte Vec struct first. We'd also have to bake in the typed length
// TODO : somewhere outside of this serialized hunk of data.
impl<D: Clone+Abomonation> DerefMut for Content<D> {
    #[inline]
    fn deref_mut(&mut self) -> &mut Vec<D> {
        let value = if let Content::Bytes(ref mut bytes, offset, _length) = *self {
            let data: &Vec<D> = unsafe { ::std::mem::transmute(bytes.get_unchecked(offset)) };
            // let (data, _) = verify::<Vec<D>>(&bytes[offset..]).unwrap();
            // ALLOC : clone() will allocate a Vec<D> and maybe more.
            Some(Content::Typed((*data).clone()))
        }
        else { None };

        if let Some(contents) = value {
            *self = contents;
        }

        if let Content::Typed(ref mut data) = *self {
            data
        }
        else { unreachable!() }
    }
}
<commit_msg>added replace_with method<commit_after>//! Core type for communicating a collection of `D: Data` records.
//!
//! `Message<D>` is meant to be treated as a `Vec<D>`, with the caveat that it may wrap either
//! typed `Vec<D>` data or binary `Vec<u8>` data that have not yet been deserialized. The type
//! implements `Deref` and `DerefMut` with `Target = Vec<D>`, whose implementations accommodate
//! the possibly serialized representation.
use timely_communication::{Serialize, Push};
use std::ops::{Deref, DerefMut};
use abomonation::{Abomonation, encode, decode};

#[derive(Clone)]
pub struct Message<T, D> {
    pub time: T,
    pub data: Content<D>,
    pub from: usize,
    pub seq: usize,
}

impl<T, D> Message<T, D> {
    #[inline]
    pub fn new(time: T, data: Content<D>, from: usize, seq: usize) -> Message<T, D> {
        Message {
            time: time,
            data: data,
            from: from,
            seq: seq,
        }
    }
}

// Implementation required to get different behavior out of communication fabric.
impl<T: Abomonation+Clone, D: Abomonation> Serialize for Message<T, D> {
    #[inline]
    fn into_bytes(&mut self, bytes: &mut Vec<u8>) {
        unsafe { encode(&self.time, bytes); }
        unsafe { encode(&self.from, bytes); }
        unsafe { encode(&self.seq, bytes); }
        let vec: &Vec<D> = self.data.deref();
        unsafe { encode(vec, bytes); }
    }
    #[inline]
    fn from_bytes(bytes: &mut Vec<u8>) -> Self {
        let mut bytes = ::std::mem::replace(bytes, Vec::new());
        let x_len = bytes.len();
        let (time, from, seq, offset) = {
            let (t,r) = unsafe { decode::<T>(&mut bytes) }.unwrap();
            let (&f,r) = unsafe { decode::<usize>(r) }.unwrap();
            let (&s,r) = unsafe { decode::<usize>(r) }.unwrap();
            let o = x_len - r.len();
            ((*t).clone(), f, s, o)
        };

        let length = unsafe { decode::<Vec<D>>(&mut bytes[offset..]) }.unwrap().0.len();
        Message::new(time, Content::Bytes(bytes, offset, length), from, seq)
    }
}

#[derive(Clone)]
pub enum Content<D> {
    Bytes(Vec<u8>, usize, usize),  // bytes[offset..] decodes to length elements
    Typed(Vec<D>),
}

// ALLOC : This Drop implementation gets *very* angry if we drop allocated data.
// ALLOC : It probably shouldn't be used in practice, but should help track down who is being
// ALLOC : bad about respecting allocated memory.
// impl<D> Drop for Message<D> {
//     match self.contents {
//         Content::Bytes(bytes, _, _) => { assert!(bytes.capacity() == 0); }
//         Content::Typed(typed) => { assert!(typed.capacity() == 0); }
//     }
// }

impl<D> Content<D> {
    /// Default number of elements in a typed allocated message. This could vary as a function of
    /// `std::mem::size_of::<D>()`, so is left as a method rather than a constant.
    #[inline]
    pub fn default_length() -> usize { 4096 }

    /// The length of the underlying typed vector.
    ///
    /// The length is tracked without needing to deserialize the data, so that this method can be
    /// called even for `D` that do not implement `Serializable`.
    #[inline]
    pub fn len(&self) -> usize {
        match *self {
            Content::Bytes(_, _, length) => length,
            Content::Typed(ref data) => data.len(),
        }
    }

    /// Constructs a `Message` from typed data, replacing its argument with `Vec::new()`.
    #[inline]
    pub fn from_typed(typed: &mut Vec<D>) -> Content<D> {
        Content::Typed(::std::mem::replace(typed, Vec::new()))
    }

    /// Returns the typed vector, cleared, or a Vec::new() if the data are binary (and drops them
    /// on the floor, I guess! Ouch.
    /// ALLOC : dropping of binary data. likely called only by persons who pushed typed data on,
    /// ALLOC : so perhaps not all that common. Could put a panic! here just for fun! :D
    /// ALLOC : casual dropping of contents of `data`, which might have allocated memory.
    #[inline]
    pub fn into_typed(self) -> Vec<D> {
        match self {
            Content::Bytes(_,_,_) => Vec::new(),
            Content::Typed(mut data) => { data.clear(); data },
        }
    }

    #[inline]
    pub fn push_at<T, P: Push<(T, Content<D>)>>(buffer: &mut Vec<D>, time: T, pusher: &mut P) {

        let data = Content::from_typed(buffer);
        let mut message = Some((time, data));

        pusher.push(&mut message);

        if let Some((_, Content::Typed(mut typed))) = message {
            typed.clear();
            *buffer = typed;
        }
        else {
            *buffer = Vec::with_capacity(Content::<D>::default_length());
        }

        // TODO : Assert failing, but not sure if is bug when deser can make arbitrary lengths
        // TODO : in clone. Revisit!
        // assert!(buffer.capacity() == Content::<D>::default_length());
        if buffer.capacity() != Content::<D>::default_length() {
            *buffer = Vec::with_capacity(Content::<D>::default_length());
        }
    }
}

impl<D: Clone+Abomonation> Content<D> {
    #[inline]
    pub fn replace_with(&mut self, other: Vec<D>) -> Vec<D> {
        ::std::mem::replace(self.deref_mut(), other)
    }
}

impl<D: Abomonation> Deref for Content<D> {
    type Target = Vec<D>;
    #[inline]
    fn deref(&self) -> &Vec<D> {
        match *self {
            Content::Bytes(ref bytes, offset, _length) => {
                // verify wasn't actually safe, it turns out...
                unsafe { ::std::mem::transmute(bytes.get_unchecked(offset)) }
            },
            Content::Typed(ref data) => data,
        }
    }
}

// TODO : Rather than .clone() the decoded data, we should try and re-rig serialization so that the
// TODO : underlying byte array can just be handed to Vec::from_raw_parts, cloning any owned data.
// TODO : I think we would need to make sure that the byte array had the right alignment, so that
// TODO : when the Vec is eventually dropped we don't de-allocate the wrong number of bytes.
// TODO : This requires mucking with the Abomonation code, as it doesn't currently let you step in
// TODO : and skip copying the 24 byte Vec struct first. We'd also have to bake in the typed length
// TODO : somewhere outside of this serialized hunk of data.
impl<D: Clone+Abomonation> DerefMut for Content<D> {
    #[inline]
    fn deref_mut(&mut self) -> &mut Vec<D> {
        let value = if let Content::Bytes(ref mut bytes, offset, _length) = *self {
            let data: &Vec<D> = unsafe { ::std::mem::transmute(bytes.get_unchecked(offset)) };
            // let (data, _) = verify::<Vec<D>>(&bytes[offset..]).unwrap();
            // ALLOC : clone() will allocate a Vec<D> and maybe more.
            Some(Content::Typed((*data).clone()))
        }
        else { None };

        if let Some(contents) = value {
            *self = contents;
        }

        if let Content::Typed(ref mut data) = *self {
            data
        }
        else { unreachable!() }
    }
}
<|endoftext|>


<commit_before>// Copyright 2019 The Exonum Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

pub use self::{
    configure::{Configure, ConfigureCall, CONFIGURE_INTERFACE_NAME},
    errors::Error,
    proto_structures::{
        ConfigChange, ConfigProposalWithHash, ConfigPropose, ConfigVote, DeployConfirmation,
        DeployRequest, ServiceConfig, StartService,
    },
    schema::Schema,
    transactions::SupervisorInterface,
};

use exonum::{
    blockchain::InstanceCollection,
    crypto::Hash,
    runtime::{
        api::ServiceApiBuilder,
        rust::{AfterCommitContext, CallContext, Service, Transaction},
        BlockchainData, InstanceId, SUPERVISOR_INSTANCE_ID,
    },
};
use exonum_derive::*;
use exonum_merkledb::Snapshot;

pub mod mode;

mod api;
mod configure;
mod errors;
mod proto;
mod proto_structures;
mod schema;
mod transactions;

/// Instance identifier for first deployed service.
///
/// By analogy with the privileged ports of the network, we use a range 0..1023 of instance
/// identifiers for built-in services which can be created only during the blockchain genesis
/// block creation.
// TODO: remove [ECR-3851]
const MAX_BUILTIN_INSTANCE_ID: InstanceId = 1024;

/// Decentralized supervisor.
pub type DecentralizedSupervisor = Supervisor<mode::Decentralized>;

/// Simple supervisor.
pub type SimpleSupervisor = Supervisor<mode::Simple>;

/// Returns the `Supervisor` entity name.
pub const fn supervisor_name() -> &'static str {
    Supervisor::<mode::Decentralized>::NAME
}

/// Error message emitted when the `Supervisor` is installed as a non-privileged service.
const NOT_SUPERVISOR_MSG: &str = "`Supervisor` is installed as a non-privileged service. \
                                  For correct operation, `Supervisor` needs to have numeric ID 0.";

/// Applies configuration changes.
/// Upon any failure, execution of this method stops and `Err(())` is returned.
fn update_configs(context: &mut CallContext<'_>, changes: Vec<ConfigChange>) -> Result<(), ()> {
    for change in changes.into_iter() {
        match change {
            ConfigChange::Consensus(config) => {
                log::trace!("Updating consensus configuration {:?}", config);

                context
                    .writeable_core_schema()
                    .consensus_config_entry()
                    .set(config);
            }

            ConfigChange::Service(config) => {
                log::trace!(
                    "Updating service instance configuration, instance ID is {}",
                    config.instance_id
                );

                // `ConfigureCall` interface was checked during the config verifying
                // so panic on `expect` here is unlikely and means a bug in the implementation.
                context
                    .interface::<ConfigureCall<'_>>(config.instance_id)
                    .expect("Obtaining Configure interface failed")
                    .apply_config(config.params.clone())
                    .map_err(|e| {
                        log::error!(
                            "An error occurred while applying service configuration. {}",
                            e
                        );
                    })?;
            }

            ConfigChange::StartService(start_service) => {
                log::trace!(
                    "Request add service with name {:?} from artifact {:?}",
                    start_service.name,
                    start_service.artifact
                );
            let id = Schema::new(context.service_data()).assign_instance_id();
            let (instance_spec, config) = start_service.into_parts(id);

            context.start_adding_service(instance_spec, config)
                    .map_err(|e| {
                        log::error!("Service start request failed. {}", e);
                    })?;
            }
        }
    }
    Ok(())
}

#[derive(Debug, Default, Clone, ServiceFactory, ServiceDispatcher)]
#[service_dispatcher(implements("transactions::SupervisorInterface"))]
#[service_factory(
    proto_sources = "proto",
    artifact_name = "exonum-supervisor",
    service_constructor = "Self::construct"
)]
pub struct Supervisor<Mode>
where
    Mode: mode::SupervisorMode,
{
    phantom: std::marker::PhantomData<Mode>,
}

impl<Mode> Supervisor<Mode>
where
    Mode: mode::SupervisorMode,
{
    /// Name of the supervisor service.
    pub const NAME: &'static str = "supervisor";

    pub fn new() -> Supervisor<Mode> {
        Supervisor {
            phantom: std::marker::PhantomData::<Mode>::default(),
        }
    }

    pub fn construct(&self) -> Box<Self> {
        Box::new(Self::new())
    }
}

impl<Mode> Service for Supervisor<Mode>
where
    Mode: mode::SupervisorMode,
{
    fn state_hash(&self, data: BlockchainData<&dyn Snapshot>) -> Vec<Hash> {
        Schema::new(data.for_executing_service()).state_hash()
    }

    fn before_commit(&self, mut context: CallContext<'_>) {
        let mut schema = Schema::new(context.service_data());
        let core_schema = context.data().for_core();
        let validator_count = core_schema.consensus_config().validator_keys.len();
        let height = core_schema.height();

        // Removes pending deploy requests for which deadline was exceeded.
        let requests_to_remove = schema
            .pending_deployments
            .values()
            .filter(|request| request.deadline_height < height)
            .collect::<Vec<_>>();

        for request in requests_to_remove {
            schema.pending_deployments.remove(&request.artifact);
            log::trace!("Removed outdated deployment request {:?}", request);
        }

        let entry = schema.pending_proposal.get();
        if let Some(entry) = entry {
            if entry.config_propose.actual_from <= height {
                // Remove pending config proposal for which deadline was exceeded.
                log::trace!("Removed outdated config proposal");
                schema.pending_proposal.remove();
            } else if entry.config_propose.actual_from == height.next() {
                // Config should be applied at the next height.
                if Mode::config_approved(
                    &entry.propose_hash,
                    &schema.config_confirms,
                    validator_count,
                ) {
                    log::info!(
                        "New configuration has been accepted: {:?}",
                        entry.config_propose
                    );

                    // Remove config from proposals.
                    // If the config update will fail, this entry will be restored due to rollback.
                    // However, it won't be actual anymore and will be removed at the next height.
                    schema.pending_proposal.remove();
                    drop(schema);

                    // Perform the application of configs.
                    let update_result = update_configs(&mut context, entry.config_propose.changes);

                    if update_result.is_err() {
                        // Panic will cause changes to be rolled back.
                        // TODO: Return error instead of panic once the signature
                        // of `before_commit` will allow it. [ECR-3811]
                        panic!("Config update failed")
                    }
                }
            }
        }
    }

    fn after_commit(&self, mut context: AfterCommitContext<'_>) {
        let schema = Schema::new(context.service_data());
        let keypair = context.service_keypair;
        let instance_id = context.instance.id;
        let core_schema = context.data().for_core();
        let is_validator = core_schema
            .validator_id(context.service_keypair.0)
            .is_some();

        // Sends confirmation transaction for unconfirmed deployment requests.
        let deployments: Vec<_> = schema
            .pending_deployments
            .values()
            .filter(|request| {
                let confirmation = DeployConfirmation::from(request.clone());
                !schema
                    .deploy_confirmations
                    .confirmed_by(&confirmation, &keypair.0)
            })
            .collect();
        drop(schema);

        for unconfirmed_request in deployments {
            let artifact = unconfirmed_request.artifact.clone();
            let spec = unconfirmed_request.spec.clone();
            let keypair = context.service_keypair.clone();
            let tx_sender = context.transaction_broadcaster();

            let mut extensions = context.supervisor_extensions().expect(NOT_SUPERVISOR_MSG);
            extensions.start_deploy(artifact, spec, move || {
                if is_validator {
                    log::trace!(
                        "Sending confirmation for deployment request {:?}",
                        unconfirmed_request
                    );

                    let transaction = DeployConfirmation::from(unconfirmed_request);
                    tx_sender
                        .broadcast_transaction(transaction.sign(instance_id, keypair.0, &keypair.1))
                        .map_err(|e| log::error!("Couldn't broadcast transaction {}", e))
                        .ok();
                }
                Ok(())
            });
        }
    }

    fn wire_api(&self, builder: &mut ServiceApiBuilder) {
        api::wire(builder)
    }
}

impl<Mode> From<Supervisor<Mode>> for InstanceCollection
where
    Mode: mode::SupervisorMode,
{
    fn from(service: Supervisor<Mode>) -> Self {
        InstanceCollection::new(service).with_instance(
            SUPERVISOR_INSTANCE_ID,
            Supervisor::<Mode>::NAME,
            Vec::default(),
        )
    }
}
<commit_msg>Fix formatting<commit_after>// Copyright 2019 The Exonum Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

pub use self::{
    configure::{Configure, ConfigureCall, CONFIGURE_INTERFACE_NAME},
    errors::Error,
    proto_structures::{
        ConfigChange, ConfigProposalWithHash, ConfigPropose, ConfigVote, DeployConfirmation,
        DeployRequest, ServiceConfig, StartService,
    },
    schema::Schema,
    transactions::SupervisorInterface,
};

use exonum::{
    blockchain::InstanceCollection,
    crypto::Hash,
    runtime::{
        api::ServiceApiBuilder,
        rust::{AfterCommitContext, CallContext, Service, Transaction},
        BlockchainData, InstanceId, SUPERVISOR_INSTANCE_ID,
    },
};
use exonum_derive::*;
use exonum_merkledb::Snapshot;

pub mod mode;

mod api;
mod configure;
mod errors;
mod proto;
mod proto_structures;
mod schema;
mod transactions;

/// Instance identifier for first deployed service.
///
/// By analogy with the privileged ports of the network, we use a range 0..1023 of instance
/// identifiers for built-in services which can be created only during the blockchain genesis
/// block creation.
// TODO: remove [ECR-3851]
const MAX_BUILTIN_INSTANCE_ID: InstanceId = 1024;

/// Decentralized supervisor.
pub type DecentralizedSupervisor = Supervisor<mode::Decentralized>;

/// Simple supervisor.
pub type SimpleSupervisor = Supervisor<mode::Simple>;

/// Returns the `Supervisor` entity name.
pub const fn supervisor_name() -> &'static str {
    Supervisor::<mode::Decentralized>::NAME
}

/// Error message emitted when the `Supervisor` is installed as a non-privileged service.
const NOT_SUPERVISOR_MSG: &str = "`Supervisor` is installed as a non-privileged service. \
                                  For correct operation, `Supervisor` needs to have numeric ID 0.";

/// Applies configuration changes.
/// Upon any failure, execution of this method stops and `Err(())` is returned.
fn update_configs(context: &mut CallContext<'_>, changes: Vec<ConfigChange>) -> Result<(), ()> {
    for change in changes.into_iter() {
        match change {
            ConfigChange::Consensus(config) => {
                log::trace!("Updating consensus configuration {:?}", config);

                context
                    .writeable_core_schema()
                    .consensus_config_entry()
                    .set(config);
            }

            ConfigChange::Service(config) => {
                log::trace!(
                    "Updating service instance configuration, instance ID is {}",
                    config.instance_id
                );

                // `ConfigureCall` interface was checked during the config verifying
                // so panic on `expect` here is unlikely and means a bug in the implementation.
                context
                    .interface::<ConfigureCall<'_>>(config.instance_id)
                    .expect("Obtaining Configure interface failed")
                    .apply_config(config.params.clone())
                    .map_err(|e| {
                        log::error!(
                            "An error occurred while applying service configuration. {}",
                            e
                        );
                    })?;
            }

            ConfigChange::StartService(start_service) => {
                log::trace!(
                    "Request add service with name {:?} from artifact {:?}",
                    start_service.name,
                    start_service.artifact
                );
                let id = Schema::new(context.service_data()).assign_instance_id();
                let (instance_spec, config) = start_service.into_parts(id);

                context
                    .start_adding_service(instance_spec, config)
                    .map_err(|e| {
                        log::error!("Service start request failed. {}", e);
                    })?;
            }
        }
    }
    Ok(())
}

#[derive(Debug, Default, Clone, ServiceFactory, ServiceDispatcher)]
#[service_dispatcher(implements("transactions::SupervisorInterface"))]
#[service_factory(
    proto_sources = "proto",
    artifact_name = "exonum-supervisor",
    service_constructor = "Self::construct"
)]
pub struct Supervisor<Mode>
where
    Mode: mode::SupervisorMode,
{
    phantom: std::marker::PhantomData<Mode>,
}

impl<Mode> Supervisor<Mode>
where
    Mode: mode::SupervisorMode,
{
    /// Name of the supervisor service.
    pub const NAME: &'static str = "supervisor";

    pub fn new() -> Supervisor<Mode> {
        Supervisor {
            phantom: std::marker::PhantomData::<Mode>::default(),
        }
    }

    pub fn construct(&self) -> Box<Self> {
        Box::new(Self::new())
    }
}

impl<Mode> Service for Supervisor<Mode>
where
    Mode: mode::SupervisorMode,
{
    fn state_hash(&self, data: BlockchainData<&dyn Snapshot>) -> Vec<Hash> {
        Schema::new(data.for_executing_service()).state_hash()
    }

    fn before_commit(&self, mut context: CallContext<'_>) {
        let mut schema = Schema::new(context.service_data());
        let core_schema = context.data().for_core();
        let validator_count = core_schema.consensus_config().validator_keys.len();
        let height = core_schema.height();

        // Removes pending deploy requests for which deadline was exceeded.
        let requests_to_remove = schema
            .pending_deployments
            .values()
            .filter(|request| request.deadline_height < height)
            .collect::<Vec<_>>();

        for request in requests_to_remove {
            schema.pending_deployments.remove(&request.artifact);
            log::trace!("Removed outdated deployment request {:?}", request);
        }

        let entry = schema.pending_proposal.get();
        if let Some(entry) = entry {
            if entry.config_propose.actual_from <= height {
                // Remove pending config proposal for which deadline was exceeded.
                log::trace!("Removed outdated config proposal");
                schema.pending_proposal.remove();
            } else if entry.config_propose.actual_from == height.next() {
                // Config should be applied at the next height.
                if Mode::config_approved(
                    &entry.propose_hash,
                    &schema.config_confirms,
                    validator_count,
                ) {
                    log::info!(
                        "New configuration has been accepted: {:?}",
                        entry.config_propose
                    );

                    // Remove config from proposals.
                    // If the config update will fail, this entry will be restored due to rollback.
                    // However, it won't be actual anymore and will be removed at the next height.
                    schema.pending_proposal.remove();
                    drop(schema);

                    // Perform the application of configs.
                    let update_result = update_configs(&mut context, entry.config_propose.changes);

                    if update_result.is_err() {
                        // Panic will cause changes to be rolled back.
                        // TODO: Return error instead of panic once the signature
                        // of `before_commit` will allow it. [ECR-3811]
                        panic!("Config update failed")
                    }
                }
            }
        }
    }

    fn after_commit(&self, mut context: AfterCommitContext<'_>) {
        let schema = Schema::new(context.service_data());
        let keypair = context.service_keypair;
        let instance_id = context.instance.id;
        let core_schema = context.data().for_core();
        let is_validator = core_schema
            .validator_id(context.service_keypair.0)
            .is_some();

        // Sends confirmation transaction for unconfirmed deployment requests.
        let deployments: Vec<_> = schema
            .pending_deployments
            .values()
            .filter(|request| {
                let confirmation = DeployConfirmation::from(request.clone());
                !schema
                    .deploy_confirmations
                    .confirmed_by(&confirmation, &keypair.0)
            })
            .collect();
        drop(schema);

        for unconfirmed_request in deployments {
            let artifact = unconfirmed_request.artifact.clone();
            let spec = unconfirmed_request.spec.clone();
            let keypair = context.service_keypair.clone();
            let tx_sender = context.transaction_broadcaster();

            let mut extensions = context.supervisor_extensions().expect(NOT_SUPERVISOR_MSG);
            extensions.start_deploy(artifact, spec, move || {
                if is_validator {
                    log::trace!(
                        "Sending confirmation for deployment request {:?}",
                        unconfirmed_request
                    );

                    let transaction = DeployConfirmation::from(unconfirmed_request);
                    tx_sender
                        .broadcast_transaction(transaction.sign(instance_id, keypair.0, &keypair.1))
                        .map_err(|e| log::error!("Couldn't broadcast transaction {}", e))
                        .ok();
                }
                Ok(())
            });
        }
    }

    fn wire_api(&self, builder: &mut ServiceApiBuilder) {
        api::wire(builder)
    }
}

impl<Mode> From<Supervisor<Mode>> for InstanceCollection
where
    Mode: mode::SupervisorMode,
{
    fn from(service: Supervisor<Mode>) -> Self {
        InstanceCollection::new(service).with_instance(
            SUPERVISOR_INSTANCE_ID,
            Supervisor::<Mode>::NAME,
            Vec::default(),
        )
    }
}
<|endoftext|>


<commit_before>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Searching for information from the cstore

use metadata::common::*;
use metadata::cstore;
use metadata::decoder;
use middle::ty;
use middle::typeck;

use std::vec;
use reader = extra::ebml::reader;
use syntax::ast;
use syntax::ast_map;
use syntax::diagnostic::expect;

pub struct StaticMethodInfo {
    ident: ast::Ident,
    def_id: ast::DefId,
    purity: ast::Purity,
    vis: ast::Visibility,
}

pub fn get_symbol(cstore: @cstore::CStore, def: ast::DefId) -> ~str {
    let cdata = cstore.get_crate_data(def.crate).data();
    return decoder::get_symbol(cdata, def.node);
}

pub fn get_type_param_count(cstore: @cstore::CStore, def: ast::DefId)
                         -> uint {
    let cdata = cstore.get_crate_data(def.crate).data();
    return decoder::get_type_param_count(cdata, def.node);
}

/// Iterates over all the language items in the given crate.
pub fn each_lang_item(cstore: @cstore::CStore,
                      cnum: ast::CrateNum,
                      f: |ast::NodeId, uint| -> bool)
                      -> bool {
    let crate_data = cstore.get_crate_data(cnum);
    decoder::each_lang_item(crate_data, f)
}

/// Iterates over each child of the given item.
pub fn each_child_of_item(cstore: @cstore::CStore,
                          def_id: ast::DefId,
                          callback: |decoder::DefLike,
                                     ast::Ident,
                                     ast::Visibility|) {
    let crate_data = cstore.get_crate_data(def_id.crate);
    let get_crate_data: decoder::GetCrateDataCb = |cnum| {
        cstore.get_crate_data(cnum)
    };
    decoder::each_child_of_item(cstore.intr,
                                crate_data,
                                def_id.node,
                                get_crate_data,
                                callback)
}

/// Iterates over each top-level crate item.
pub fn each_top_level_item_of_crate(cstore: @cstore::CStore,
                                    cnum: ast::CrateNum,
                                    callback: |decoder::DefLike,
                                               ast::Ident,
                                               ast::Visibility|) {
    let crate_data = cstore.get_crate_data(cnum);
    let get_crate_data: decoder::GetCrateDataCb = |cnum| {
        cstore.get_crate_data(cnum)
    };
    decoder::each_top_level_item_of_crate(cstore.intr,
                                          crate_data,
                                          get_crate_data,
                                          callback)
}

pub fn get_item_path(tcx: ty::ctxt, def: ast::DefId) -> ast_map::Path {
    let cstore = tcx.cstore;
    let cdata = cstore.get_crate_data(def.crate);
    let path = decoder::get_item_path(cdata, def.node);

    // FIXME #1920: This path is not always correct if the crate is not linked
    // into the root namespace.
    vec::append(~[ast_map::PathMod(tcx.sess.ident_of(
        cdata.name))], path)
}

pub enum found_ast {
    found(ast::InlinedItem),
    found_parent(ast::DefId, ast::InlinedItem),
    not_found,
}

// Finds the AST for this item in the crate metadata, if any.  If the item was
// not marked for inlining, then the AST will not be present and hence none
// will be returned.
pub fn maybe_get_item_ast(tcx: ty::ctxt, def: ast::DefId,
                          decode_inlined_item: decoder::decode_inlined_item)
                       -> found_ast {
    let cstore = tcx.cstore;
    let cdata = cstore.get_crate_data(def.crate);
    decoder::maybe_get_item_ast(cdata, tcx, def.node,
                                decode_inlined_item)
}

pub fn get_enum_variants(tcx: ty::ctxt, def: ast::DefId)
                      -> ~[@ty::VariantInfo] {
    let cstore = tcx.cstore;
    let cdata = cstore.get_crate_data(def.crate);
    return decoder::get_enum_variants(cstore.intr, cdata, def.node, tcx)
}

/// Returns information about the given implementation.
pub fn get_impl(tcx: ty::ctxt, impl_def_id: ast::DefId)
                -> ty::Impl {
    let cdata = tcx.cstore.get_crate_data(impl_def_id.crate);
    decoder::get_impl(tcx.cstore.intr, cdata, impl_def_id.node, tcx)
}

pub fn get_method(tcx: ty::ctxt, def: ast::DefId) -> ty::Method {
    let cdata = tcx.cstore.get_crate_data(def.crate);
    decoder::get_method(tcx.cstore.intr, cdata, def.node, tcx)
}

pub fn get_method_name_and_explicit_self(cstore: @cstore::CStore,
                                         def: ast::DefId)
                                     -> (ast::Ident, ast::ExplicitSelf_)
{
    let cdata = cstore.get_crate_data(def.crate);
    decoder::get_method_name_and_explicit_self(cstore.intr, cdata, def.node)
}

pub fn get_trait_method_def_ids(cstore: @cstore::CStore,
                                def: ast::DefId) -> ~[ast::DefId] {
    let cdata = cstore.get_crate_data(def.crate);
    decoder::get_trait_method_def_ids(cdata, def.node)
}

pub fn get_item_variances(cstore: @cstore::CStore,
                          def: ast::DefId) -> ty::ItemVariances {
    let cdata = cstore.get_crate_data(def.crate);
    decoder::get_item_variances(cdata, def.node)
}

pub fn get_provided_trait_methods(tcx: ty::ctxt,
                                  def: ast::DefId)
                               -> ~[@ty::Method] {
    let cstore = tcx.cstore;
    let cdata = cstore.get_crate_data(def.crate);
    decoder::get_provided_trait_methods(cstore.intr, cdata, def.node, tcx)
}

pub fn get_supertraits(tcx: ty::ctxt, def: ast::DefId) -> ~[@ty::TraitRef] {
    let cstore = tcx.cstore;
    let cdata = cstore.get_crate_data(def.crate);
    decoder::get_supertraits(cdata, def.node, tcx)
}

pub fn get_type_name_if_impl(cstore: @cstore::CStore, def: ast::DefId)
                          -> Option<ast::Ident> {
    let cdata = cstore.get_crate_data(def.crate);
    decoder::get_type_name_if_impl(cdata, def.node)
}

pub fn get_static_methods_if_impl(cstore: @cstore::CStore,
                                  def: ast::DefId)
                               -> Option<~[StaticMethodInfo]> {
    let cdata = cstore.get_crate_data(def.crate);
    decoder::get_static_methods_if_impl(cstore.intr, cdata, def.node)
}

pub fn get_item_attrs(cstore: @cstore::CStore,
                      def_id: ast::DefId,
                      f: |~[@ast::MetaItem]|) {
    let cdata = cstore.get_crate_data(def_id.crate);
    decoder::get_item_attrs(cdata, def_id.node, f)
}

pub fn get_struct_fields(cstore: @cstore::CStore,
                         def: ast::DefId)
                      -> ~[ty::field_ty] {
    let cdata = cstore.get_crate_data(def.crate);
    decoder::get_struct_fields(cstore.intr, cdata, def.node)
}

pub fn get_type(tcx: ty::ctxt,
                def: ast::DefId)
             -> ty::ty_param_bounds_and_ty {
    let cstore = tcx.cstore;
    let cdata = cstore.get_crate_data(def.crate);
    decoder::get_type(cdata, def.node, tcx)
}

pub fn get_trait_def(tcx: ty::ctxt, def: ast::DefId) -> ty::TraitDef {
    let cstore = tcx.cstore;
    let cdata = cstore.get_crate_data(def.crate);
    decoder::get_trait_def(cdata, def.node, tcx)
}

pub fn get_field_type(tcx: ty::ctxt, class_id: ast::DefId,
                      def: ast::DefId) -> ty::ty_param_bounds_and_ty {
    let cstore = tcx.cstore;
    let cdata = cstore.get_crate_data(class_id.crate);
    let all_items = reader::get_doc(reader::Doc(cdata.data()), tag_items);
    debug!("Looking up {:?}", class_id);
    let class_doc = expect(tcx.diag,
                           decoder::maybe_find_item(class_id.node, all_items),
                           || format!("get_field_type: class ID {:?} not found",
                                   class_id) );
    debug!("looking up {:?} : {:?}", def, class_doc);
    let the_field = expect(tcx.diag,
        decoder::maybe_find_item(def.node, class_doc),
        || format!("get_field_type: in class {:?}, field ID {:?} not found",
                 class_id, def) );
    debug!("got field data {:?}", the_field);
    let ty = decoder::item_type(def, the_field, tcx, cdata);
    ty::ty_param_bounds_and_ty {
        generics: ty::Generics {type_param_defs: @~[],
                                region_param_defs: @[]},
        ty: ty
    }
}

// Given a def_id for an impl, return the trait it implements,
// if there is one.
pub fn get_impl_trait(tcx: ty::ctxt,
                      def: ast::DefId) -> Option<@ty::TraitRef> {
    let cstore = tcx.cstore;
    let cdata = cstore.get_crate_data(def.crate);
    decoder::get_impl_trait(cdata, def.node, tcx)
}

// Given a def_id for an impl, return information about its vtables
pub fn get_impl_vtables(tcx: ty::ctxt,
                        def: ast::DefId) -> typeck::impl_res {
    let cstore = tcx.cstore;
    let cdata = cstore.get_crate_data(def.crate);
    decoder::get_impl_vtables(cdata, def.node, tcx)
}

pub fn get_impl_method(cstore: @cstore::CStore,
                       def: ast::DefId,
                       mname: ast::Ident)
                    -> Option<ast::DefId> {
    let cdata = cstore.get_crate_data(def.crate);
    decoder::get_impl_method(cstore.intr, cdata, def.node, mname)
}

pub fn get_item_visibility(cstore: @cstore::CStore,
                           def_id: ast::DefId)
                        -> ast::Visibility {
    let cdata = cstore.get_crate_data(def_id.crate);
    decoder::get_item_visibility(cdata, def_id.node)
}

pub fn get_native_libraries(cstore: @cstore::CStore,
                            crate_num: ast::CrateNum)
                                -> ~[(cstore::NativeLibaryKind, ~str)] {
    let cdata = cstore.get_crate_data(crate_num);
    decoder::get_native_libraries(cdata)
}

pub fn each_impl(cstore: @cstore::CStore,
                 crate_num: ast::CrateNum,
                 callback: |ast::DefId|) {
    let cdata = cstore.get_crate_data(crate_num);
    decoder::each_impl(cdata, callback)
}

pub fn each_implementation_for_type(cstore: @cstore::CStore,
                                    def_id: ast::DefId,
                                    callback: |ast::DefId|) {
    let cdata = cstore.get_crate_data(def_id.crate);
    decoder::each_implementation_for_type(cdata, def_id.node, callback)
}

pub fn each_implementation_for_trait(cstore: @cstore::CStore,
                                     def_id: ast::DefId,
                                     callback: |ast::DefId|) {
    let cdata = cstore.get_crate_data(def_id.crate);
    decoder::each_implementation_for_trait(cdata, def_id.node, callback)
}

/// If the given def ID describes a method belonging to a trait (either a
/// default method or an implementation of a trait method), returns the ID of
/// the trait that the method belongs to. Otherwise, returns `None`.
pub fn get_trait_of_method(cstore: @cstore::CStore,
                           def_id: ast::DefId,
                           tcx: ty::ctxt)
                           -> Option<ast::DefId> {
    let cdata = cstore.get_crate_data(def_id.crate);
    decoder::get_trait_of_method(cdata, def_id.node, tcx)
}

pub fn get_macro_registrar_fn(cstore: @cstore::CStore,
                              crate_num: ast::CrateNum)
                              -> Option<ast::DefId> {
    let cdata = cstore.get_crate_data(crate_num);
    decoder::get_macro_registrar_fn(cdata)
}

pub fn get_exported_macros(cstore: @cstore::CStore,
                           crate_num: ast::CrateNum)
                           -> ~[@ast::Item] {
    let cdata = cstore.get_crate_data(crate_num);
    decoder::get_exported_macros(cdata)
}
<commit_msg>auto merge of #11701 : FeGs/rust/stray-debug-in-metadata, r=alexcrichton<commit_after>// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Searching for information from the cstore

use metadata::common::*;
use metadata::cstore;
use metadata::decoder;
use middle::ty;
use middle::typeck;

use std::vec;
use reader = extra::ebml::reader;
use syntax::ast;
use syntax::ast_map;
use syntax::diagnostic::expect;

pub struct StaticMethodInfo {
    ident: ast::Ident,
    def_id: ast::DefId,
    purity: ast::Purity,
    vis: ast::Visibility,
}

pub fn get_symbol(cstore: @cstore::CStore, def: ast::DefId) -> ~str {
    let cdata = cstore.get_crate_data(def.crate).data();
    return decoder::get_symbol(cdata, def.node);
}

pub fn get_type_param_count(cstore: @cstore::CStore, def: ast::DefId)
                         -> uint {
    let cdata = cstore.get_crate_data(def.crate).data();
    return decoder::get_type_param_count(cdata, def.node);
}

/// Iterates over all the language items in the given crate.
pub fn each_lang_item(cstore: @cstore::CStore,
                      cnum: ast::CrateNum,
                      f: |ast::NodeId, uint| -> bool)
                      -> bool {
    let crate_data = cstore.get_crate_data(cnum);
    decoder::each_lang_item(crate_data, f)
}

/// Iterates over each child of the given item.
pub fn each_child_of_item(cstore: @cstore::CStore,
                          def_id: ast::DefId,
                          callback: |decoder::DefLike,
                                     ast::Ident,
                                     ast::Visibility|) {
    let crate_data = cstore.get_crate_data(def_id.crate);
    let get_crate_data: decoder::GetCrateDataCb = |cnum| {
        cstore.get_crate_data(cnum)
    };
    decoder::each_child_of_item(cstore.intr,
                                crate_data,
                                def_id.node,
                                get_crate_data,
                                callback)
}

/// Iterates over each top-level crate item.
pub fn each_top_level_item_of_crate(cstore: @cstore::CStore,
                                    cnum: ast::CrateNum,
                                    callback: |decoder::DefLike,
                                               ast::Ident,
                                               ast::Visibility|) {
    let crate_data = cstore.get_crate_data(cnum);
    let get_crate_data: decoder::GetCrateDataCb = |cnum| {
        cstore.get_crate_data(cnum)
    };
    decoder::each_top_level_item_of_crate(cstore.intr,
                                          crate_data,
                                          get_crate_data,
                                          callback)
}

pub fn get_item_path(tcx: ty::ctxt, def: ast::DefId) -> ast_map::Path {
    let cstore = tcx.cstore;
    let cdata = cstore.get_crate_data(def.crate);
    let path = decoder::get_item_path(cdata, def.node);

    // FIXME #1920: This path is not always correct if the crate is not linked
    // into the root namespace.
    vec::append(~[ast_map::PathMod(tcx.sess.ident_of(
        cdata.name))], path)
}

pub enum found_ast {
    found(ast::InlinedItem),
    found_parent(ast::DefId, ast::InlinedItem),
    not_found,
}

// Finds the AST for this item in the crate metadata, if any.  If the item was
// not marked for inlining, then the AST will not be present and hence none
// will be returned.
pub fn maybe_get_item_ast(tcx: ty::ctxt, def: ast::DefId,
                          decode_inlined_item: decoder::decode_inlined_item)
                       -> found_ast {
    let cstore = tcx.cstore;
    let cdata = cstore.get_crate_data(def.crate);
    decoder::maybe_get_item_ast(cdata, tcx, def.node,
                                decode_inlined_item)
}

pub fn get_enum_variants(tcx: ty::ctxt, def: ast::DefId)
                      -> ~[@ty::VariantInfo] {
    let cstore = tcx.cstore;
    let cdata = cstore.get_crate_data(def.crate);
    return decoder::get_enum_variants(cstore.intr, cdata, def.node, tcx)
}

/// Returns information about the given implementation.
pub fn get_impl(tcx: ty::ctxt, impl_def_id: ast::DefId)
                -> ty::Impl {
    let cdata = tcx.cstore.get_crate_data(impl_def_id.crate);
    decoder::get_impl(tcx.cstore.intr, cdata, impl_def_id.node, tcx)
}

pub fn get_method(tcx: ty::ctxt, def: ast::DefId) -> ty::Method {
    let cdata = tcx.cstore.get_crate_data(def.crate);
    decoder::get_method(tcx.cstore.intr, cdata, def.node, tcx)
}

pub fn get_method_name_and_explicit_self(cstore: @cstore::CStore,
                                         def: ast::DefId)
                                     -> (ast::Ident, ast::ExplicitSelf_)
{
    let cdata = cstore.get_crate_data(def.crate);
    decoder::get_method_name_and_explicit_self(cstore.intr, cdata, def.node)
}

pub fn get_trait_method_def_ids(cstore: @cstore::CStore,
                                def: ast::DefId) -> ~[ast::DefId] {
    let cdata = cstore.get_crate_data(def.crate);
    decoder::get_trait_method_def_ids(cdata, def.node)
}

pub fn get_item_variances(cstore: @cstore::CStore,
                          def: ast::DefId) -> ty::ItemVariances {
    let cdata = cstore.get_crate_data(def.crate);
    decoder::get_item_variances(cdata, def.node)
}

pub fn get_provided_trait_methods(tcx: ty::ctxt,
                                  def: ast::DefId)
                               -> ~[@ty::Method] {
    let cstore = tcx.cstore;
    let cdata = cstore.get_crate_data(def.crate);
    decoder::get_provided_trait_methods(cstore.intr, cdata, def.node, tcx)
}

pub fn get_supertraits(tcx: ty::ctxt, def: ast::DefId) -> ~[@ty::TraitRef] {
    let cstore = tcx.cstore;
    let cdata = cstore.get_crate_data(def.crate);
    decoder::get_supertraits(cdata, def.node, tcx)
}

pub fn get_type_name_if_impl(cstore: @cstore::CStore, def: ast::DefId)
                          -> Option<ast::Ident> {
    let cdata = cstore.get_crate_data(def.crate);
    decoder::get_type_name_if_impl(cdata, def.node)
}

pub fn get_static_methods_if_impl(cstore: @cstore::CStore,
                                  def: ast::DefId)
                               -> Option<~[StaticMethodInfo]> {
    let cdata = cstore.get_crate_data(def.crate);
    decoder::get_static_methods_if_impl(cstore.intr, cdata, def.node)
}

pub fn get_item_attrs(cstore: @cstore::CStore,
                      def_id: ast::DefId,
                      f: |~[@ast::MetaItem]|) {
    let cdata = cstore.get_crate_data(def_id.crate);
    decoder::get_item_attrs(cdata, def_id.node, f)
}

pub fn get_struct_fields(cstore: @cstore::CStore,
                         def: ast::DefId)
                      -> ~[ty::field_ty] {
    let cdata = cstore.get_crate_data(def.crate);
    decoder::get_struct_fields(cstore.intr, cdata, def.node)
}

pub fn get_type(tcx: ty::ctxt,
                def: ast::DefId)
             -> ty::ty_param_bounds_and_ty {
    let cstore = tcx.cstore;
    let cdata = cstore.get_crate_data(def.crate);
    decoder::get_type(cdata, def.node, tcx)
}

pub fn get_trait_def(tcx: ty::ctxt, def: ast::DefId) -> ty::TraitDef {
    let cstore = tcx.cstore;
    let cdata = cstore.get_crate_data(def.crate);
    decoder::get_trait_def(cdata, def.node, tcx)
}

pub fn get_field_type(tcx: ty::ctxt, class_id: ast::DefId,
                      def: ast::DefId) -> ty::ty_param_bounds_and_ty {
    let cstore = tcx.cstore;
    let cdata = cstore.get_crate_data(class_id.crate);
    let all_items = reader::get_doc(reader::Doc(cdata.data()), tag_items);
    let class_doc = expect(tcx.diag,
                           decoder::maybe_find_item(class_id.node, all_items),
                           || format!("get_field_type: class ID {:?} not found",
                                   class_id) );
    let the_field = expect(tcx.diag,
        decoder::maybe_find_item(def.node, class_doc),
        || format!("get_field_type: in class {:?}, field ID {:?} not found",
                 class_id, def) );
    let ty = decoder::item_type(def, the_field, tcx, cdata);
    ty::ty_param_bounds_and_ty {
        generics: ty::Generics {type_param_defs: @~[],
                                region_param_defs: @[]},
        ty: ty
    }
}

// Given a def_id for an impl, return the trait it implements,
// if there is one.
pub fn get_impl_trait(tcx: ty::ctxt,
                      def: ast::DefId) -> Option<@ty::TraitRef> {
    let cstore = tcx.cstore;
    let cdata = cstore.get_crate_data(def.crate);
    decoder::get_impl_trait(cdata, def.node, tcx)
}

// Given a def_id for an impl, return information about its vtables
pub fn get_impl_vtables(tcx: ty::ctxt,
                        def: ast::DefId) -> typeck::impl_res {
    let cstore = tcx.cstore;
    let cdata = cstore.get_crate_data(def.crate);
    decoder::get_impl_vtables(cdata, def.node, tcx)
}

pub fn get_impl_method(cstore: @cstore::CStore,
                       def: ast::DefId,
                       mname: ast::Ident)
                    -> Option<ast::DefId> {
    let cdata = cstore.get_crate_data(def.crate);
    decoder::get_impl_method(cstore.intr, cdata, def.node, mname)
}

pub fn get_item_visibility(cstore: @cstore::CStore,
                           def_id: ast::DefId)
                        -> ast::Visibility {
    let cdata = cstore.get_crate_data(def_id.crate);
    decoder::get_item_visibility(cdata, def_id.node)
}

pub fn get_native_libraries(cstore: @cstore::CStore,
                            crate_num: ast::CrateNum)
                                -> ~[(cstore::NativeLibaryKind, ~str)] {
    let cdata = cstore.get_crate_data(crate_num);
    decoder::get_native_libraries(cdata)
}

pub fn each_impl(cstore: @cstore::CStore,
                 crate_num: ast::CrateNum,
                 callback: |ast::DefId|) {
    let cdata = cstore.get_crate_data(crate_num);
    decoder::each_impl(cdata, callback)
}

pub fn each_implementation_for_type(cstore: @cstore::CStore,
                                    def_id: ast::DefId,
                                    callback: |ast::DefId|) {
    let cdata = cstore.get_crate_data(def_id.crate);
    decoder::each_implementation_for_type(cdata, def_id.node, callback)
}

pub fn each_implementation_for_trait(cstore: @cstore::CStore,
                                     def_id: ast::DefId,
                                     callback: |ast::DefId|) {
    let cdata = cstore.get_crate_data(def_id.crate);
    decoder::each_implementation_for_trait(cdata, def_id.node, callback)
}

/// If the given def ID describes a method belonging to a trait (either a
/// default method or an implementation of a trait method), returns the ID of
/// the trait that the method belongs to. Otherwise, returns `None`.
pub fn get_trait_of_method(cstore: @cstore::CStore,
                           def_id: ast::DefId,
                           tcx: ty::ctxt)
                           -> Option<ast::DefId> {
    let cdata = cstore.get_crate_data(def_id.crate);
    decoder::get_trait_of_method(cdata, def_id.node, tcx)
}

pub fn get_macro_registrar_fn(cstore: @cstore::CStore,
                              crate_num: ast::CrateNum)
                              -> Option<ast::DefId> {
    let cdata = cstore.get_crate_data(crate_num);
    decoder::get_macro_registrar_fn(cdata)
}

pub fn get_exported_macros(cstore: @cstore::CStore,
                           crate_num: ast::CrateNum)
                           -> ~[@ast::Item] {
    let cdata = cstore.get_crate_data(crate_num);
    decoder::get_exported_macros(cdata)
}
<|endoftext|>