<commit_before>use state::State;
use context::base::BaseContext;

pub use self::handlers::ActionHandlers;
pub use self::message::MessageAction;

#[derive(Clone, Debug)]
pub enum Action {
    Message(self::message::MessageAction)
}

impl Action {
    pub fn execute(&self, state: &State, context: &BaseContext) -> ExecResult {
        let result = match *self {
            Action::Message(ref action) => action.execute(state, context)
        };

        ExecResult::from(result)
    }
}

#[derive(Debug)]
pub enum ExecResult {
    Message(self::message::ExecResult)
}

mod deser {
    use serde;
    use super::Action;

    impl serde::de::Deserialize for Action {
    fn deserialize<D>(deserializer: &mut D) -> Result<Action, D::Error>
                      where D: serde::de::Deserializer {
        enum Field {
            Message,
        }

        impl serde::de::Deserialize for Field {
            #[inline]
            fn deserialize<D>(deserializer: &mut D) -> Result<Field, D::Error>
                where D: serde::de::Deserializer {
                    struct FieldVisitor;

                    impl serde::de::Visitor for FieldVisitor {
                        type Value = Field;

                        fn visit_str<E>(&mut self, value: &str) -> Result<Field, E> where E: serde::de::Error {
                            match value {
                                "message" => Ok(Field::Message),
                                _ => Err(serde::de::Error::unknown_field(value)),
                            }
                        }
                    }

                    deserializer.visit(FieldVisitor)
                }
            }

            struct Visitor;

            impl serde::de::EnumVisitor for Visitor {
                type Value = Action;

                fn visit<V>(&mut self, mut visitor: V) -> Result<Action, V::Error>
                    where V: serde::de::VariantVisitor
                {
                    match try!(visitor.visit_variant()) {
                        Field::Message => {
                            let value = try!(visitor.visit_newtype());
                            Ok(Action::Message(value))
                        }
                    }
                }
            }

            const VARIANTS: &'static [&'static str] = &["message"];

            deserializer.visit_enum("Action", VARIANTS, Visitor)
        }
    }

    #[cfg(test)]
    mod test {
        use serde_json::from_str;
        use action::Action;

        #[test]
        fn test_given_action_when_it_is_deserialized_then_we_get_the_right_result() {
            let text = r#"
                {
                    "message": null
                }
            "#;

            let result = from_str::<Action>(text);
            println!("{:?}", &result);
            let action = result.ok().expect("Failed to deserialize a valid Action");
            match action {
                Action::Message(_) => {}
            }
        }
    }
}

pub mod handlers {
    use super::ExecResult;
    use super::message;

    pub struct ActionHandlers {
        message_handler: Box<message::ActionHandler>
    }

    impl ActionHandlers {
        pub fn new(message: Box<message::ActionHandler>) -> ActionHandlers {
            ActionHandlers {
                message_handler: message
            }
        }

        pub fn handle(&mut self, command: ExecResult) {
            match command {
                ExecResult::Message(message) => self.message_handler.handle(message)
            }
        }
    }
}

pub mod message {
    use context::base::BaseContext;
    use state::State;
    use message::{Builder, Message};

    #[derive(Debug)]
    pub struct ExecResult(Message);

    impl From<ExecResult> for super::ExecResult {
        fn from(result: ExecResult) -> super::ExecResult {
            super::ExecResult::Message(result)
        }
    }

    #[derive(Clone, Debug)]
    pub struct MessageAction;

    impl MessageAction {
        pub fn new() -> MessageAction {
            MessageAction
        }

        pub fn execute(&self, _: &State, _: &BaseContext) -> ExecResult {
            ExecResult(Builder::new("8015340d-5b44-4b16-8a3f-60b505ccd22e").build())
        }
    }

    impl From<MessageAction> for super::Action {
        fn from(action: MessageAction) -> super::Action {
            super::Action::Message(action)
        }
    }

    pub trait ActionHandler {
        fn handle(&mut self, command: ExecResult);
    }

    mod deser {

    use super::MessageAction;
    use serde;
    use serde::de::Deserialize;

    impl serde::Deserialize for MessageAction {
        fn deserialize<D>(deserializer: &mut D) -> Result<MessageAction, D::Error>
            where D: serde::de::Deserializer
        {
            deserializer.visit_unit_struct("MessageAction", MessageActionVisitor)
        }
    }

    struct MessageActionVisitor;

    impl serde::de::Visitor for MessageActionVisitor {
        type Value = MessageAction;
        fn visit_unit<E>(&mut self) -> Result<Self::Value, E>
            where E: serde::de::Error {
            Ok(MessageAction)
        }
    }
    }
}
<commit_msg>action: derive Eq<commit_after>use state::State;
use context::base::BaseContext;

pub use self::handlers::ActionHandlers;
pub use self::message::MessageAction;

#[derive(Clone, Debug, Eq, PartialEq)]
pub enum Action {
    Message(self::message::MessageAction)
}

impl Action {
    pub fn execute(&self, state: &State, context: &BaseContext) -> ExecResult {
        let result = match *self {
            Action::Message(ref action) => action.execute(state, context)
        };

        ExecResult::from(result)
    }
}

#[derive(Debug)]
pub enum ExecResult {
    Message(self::message::ExecResult)
}

mod deser {
    use serde;
    use super::Action;

    impl serde::de::Deserialize for Action {
    fn deserialize<D>(deserializer: &mut D) -> Result<Action, D::Error>
                      where D: serde::de::Deserializer {
        enum Field {
            Message,
        }

        impl serde::de::Deserialize for Field {
            #[inline]
            fn deserialize<D>(deserializer: &mut D) -> Result<Field, D::Error>
                where D: serde::de::Deserializer {
                    struct FieldVisitor;

                    impl serde::de::Visitor for FieldVisitor {
                        type Value = Field;

                        fn visit_str<E>(&mut self, value: &str) -> Result<Field, E> where E: serde::de::Error {
                            match value {
                                "message" => Ok(Field::Message),
                                _ => Err(serde::de::Error::unknown_field(value)),
                            }
                        }
                    }

                    deserializer.visit(FieldVisitor)
                }
            }

            struct Visitor;

            impl serde::de::EnumVisitor for Visitor {
                type Value = Action;

                fn visit<V>(&mut self, mut visitor: V) -> Result<Action, V::Error>
                    where V: serde::de::VariantVisitor
                {
                    match try!(visitor.visit_variant()) {
                        Field::Message => {
                            let value = try!(visitor.visit_newtype());
                            Ok(Action::Message(value))
                        }
                    }
                }
            }

            const VARIANTS: &'static [&'static str] = &["message"];

            deserializer.visit_enum("Action", VARIANTS, Visitor)
        }
    }

    #[cfg(test)]
    mod test {
        use serde_json::from_str;
        use action::Action;

        #[test]
        fn test_given_action_when_it_is_deserialized_then_we_get_the_right_result() {
            let text = r#"
                {
                    "message": null
                }
            "#;

            let result = from_str::<Action>(text);
            println!("{:?}", &result);
            let action = result.ok().expect("Failed to deserialize a valid Action");
            match action {
                Action::Message(_) => {}
            }
        }
    }
}

pub mod handlers {
    use super::ExecResult;
    use super::message;

    pub struct ActionHandlers {
        message_handler: Box<message::ActionHandler>
    }

    impl ActionHandlers {
        pub fn new(message: Box<message::ActionHandler>) -> ActionHandlers {
            ActionHandlers {
                message_handler: message
            }
        }

        pub fn handle(&mut self, command: ExecResult) {
            match command {
                ExecResult::Message(message) => self.message_handler.handle(message)
            }
        }
    }
}

pub mod message {
    use context::base::BaseContext;
    use state::State;
    use message::{Builder, Message};

    #[derive(Debug)]
    pub struct ExecResult(Message);

    impl From<ExecResult> for super::ExecResult {
        fn from(result: ExecResult) -> super::ExecResult {
            super::ExecResult::Message(result)
        }
    }

    #[derive(Clone, Debug, PartialEq, Eq)]
    pub struct MessageAction;

    impl MessageAction {
        pub fn new() -> MessageAction {
            MessageAction
        }

        pub fn execute(&self, _: &State, _: &BaseContext) -> ExecResult {
            ExecResult(Builder::new("8015340d-5b44-4b16-8a3f-60b505ccd22e").build())
        }
    }

    impl From<MessageAction> for super::Action {
        fn from(action: MessageAction) -> super::Action {
            super::Action::Message(action)
        }
    }

    pub trait ActionHandler {
        fn handle(&mut self, command: ExecResult);
    }

    mod deser {

    use super::MessageAction;
    use serde;
    use serde::de::Deserialize;

    impl serde::Deserialize for MessageAction {
        fn deserialize<D>(deserializer: &mut D) -> Result<MessageAction, D::Error>
            where D: serde::de::Deserializer
        {
            deserializer.visit_unit_struct("MessageAction", MessageActionVisitor)
        }
    }

    struct MessageActionVisitor;

    impl serde::de::Visitor for MessageActionVisitor {
        type Value = MessageAction;
        fn visit_unit<E>(&mut self) -> Result<Self::Value, E>
            where E: serde::de::Error {
            Ok(MessageAction)
        }
    }
    }
}
<|endoftext|>


<commit_before>use prolog::ast::*;
use prolog::machine::machine_state::MachineState;

use std::collections::HashSet;
use std::vec::Vec;

pub struct HeapCellPreOrderIterator<'a> {
    machine_st: &'a MachineState,
    state_stack: Vec<Addr>
}

impl<'a> HeapCellPreOrderIterator<'a> {
    pub fn new(machine_st: &'a MachineState, a: Addr) -> Self
    {
        HeapCellPreOrderIterator {
            machine_st, state_stack: vec![a]
        }
    }

    fn follow_heap(&mut self, h: usize) -> Addr
    {
        match &self.machine_st.heap[h] {
            &HeapCellValue::NamedStr(arity, _, _) => {
                for idx in (1 .. arity + 1).rev() {
                    self.state_stack.push(Addr::HeapCell(h + idx));
                }

                Addr::HeapCell(h)
            },
            &HeapCellValue::Addr(ref a) =>
                self.follow(a.clone())
        }
    }

    // called under the assumption that the location at r is about to
    // be visited, and so any follow up states need to be added to
    // state_stack. returns the dereferenced Addr from Ref.
    fn follow(&mut self, addr: Addr) -> Addr
    {
        let da = self.machine_st.store(self.machine_st.deref(addr));

        match &da {
            &Addr::Con(_) => da,
            &Addr::Lis(a) => {
                self.state_stack.push(Addr::HeapCell(a + 1));
                self.state_stack.push(Addr::HeapCell(a));

                da
            },
            &Addr::HeapCell(_) | &Addr::StackCell(_, _) =>
                da,
            &Addr::Str(s) =>
                self.follow_heap(s) // record terms of structure.
        }
    }
}

impl<'a> Iterator for HeapCellPreOrderIterator<'a> {
    type Item = HeapCellValue;

    fn next(&mut self) -> Option<Self::Item> {
        if let Some(a) = self.state_stack.pop() {
            match self.follow(a) {
                Addr::HeapCell(h) => Some(self.machine_st.heap[h].clone()),
                Addr::StackCell(fr, sc) => {
                    let heap_val = HeapCellValue::Addr(self.machine_st.and_stack[fr][sc].clone());
                    Some(heap_val)
                },
                da => Some(HeapCellValue::Addr(da))
            }
        } else {
            None
        }
    }
}

pub struct HeapCellPostOrderIterator<'a> {
    pre_iter:     HeapCellPreOrderIterator<'a>,
    parent_stack: Vec<(usize, HeapCellValue)> // number of children, parent node.
}

impl<'a> HeapCellPostOrderIterator<'a> {
    pub fn new(pre_iter: HeapCellPreOrderIterator<'a>) -> Self {
        HeapCellPostOrderIterator {
            pre_iter,
            parent_stack: vec![]
        }
    }
}

impl<'a> Iterator for HeapCellPostOrderIterator<'a> {
    type Item = HeapCellValue;

    fn next(&mut self) -> Option<Self::Item> {
        loop {
            if let Some((child_count, node)) = self.parent_stack.pop() {
                if child_count == 0 {
                    return Some(node);
                }

                self.parent_stack.push((child_count - 1, node));
            }

            if let Some(item) = self.pre_iter.next() {
                match item {
                    HeapCellValue::NamedStr(arity, name, fix) =>
                        self.parent_stack.push((arity, HeapCellValue::NamedStr(arity, name, fix))),
                    HeapCellValue::Addr(Addr::Lis(a)) =>
                        self.parent_stack.push((2, HeapCellValue::Addr(Addr::Lis(a)))),
                    child_node => {
                        return Some(child_node);
                    }
                }
            } else {
                return None;
            }
        }
    }
}

impl MachineState {
    pub fn post_order_iter<'a>(&'a self, a: Addr) -> HeapCellPostOrderIterator<'a> {
        HeapCellPostOrderIterator::new(HeapCellPreOrderIterator::new(self, a))
    }

    pub fn acyclic_pre_order_iter<'a>(&'a self, a: Addr)
                                      -> HeapCellAcyclicIterator<HeapCellPreOrderIterator<'a>>
    {
        HeapCellAcyclicIterator::new(HeapCellPreOrderIterator::new(self, a))
    }

    pub fn zipped_acyclic_pre_order_iter<'a>(&'a self, a1: Addr, a2: Addr)
                                             -> HeapCellZippedAcyclicIterator<HeapCellPreOrderIterator<'a>>
    {
        HeapCellZippedAcyclicIterator::new(HeapCellPreOrderIterator::new(self, a1),
                                           HeapCellPreOrderIterator::new(self, a2))
    }
}

pub trait MutStackHeapCellIterator {
    fn stack(&mut self) -> &mut Vec<Addr>;
}

impl<'a> MutStackHeapCellIterator for HeapCellPreOrderIterator<'a> {
    fn stack(&mut self) -> &mut Vec<Addr> {
        &mut self.state_stack
    }
}

pub struct HeapCellAcyclicIterator<HeapCellIter> {
    iter: HeapCellIter,
    seen: HashSet<Addr>
}

impl<HeapCellIter: MutStackHeapCellIterator> HeapCellAcyclicIterator<HeapCellIter>
{
    pub fn new(iter: HeapCellIter) -> Self {
        HeapCellAcyclicIterator { iter, seen: HashSet::new() }
    }
}

impl<HeapCellIter> Iterator for HeapCellAcyclicIterator<HeapCellIter>
    where HeapCellIter: Iterator<Item=HeapCellValue>
                      + MutStackHeapCellIterator
{
    type Item = HeapCellValue;

    fn next(&mut self) -> Option<Self::Item> {
        while let Some(addr) = self.iter.stack().pop() {
            if self.seen.contains(&addr) {
                continue;
            } else {
                self.iter.stack().push(addr.clone());
                self.seen.insert(addr);
                break;
            }
        }

        self.iter.next()
    }
}

pub struct HeapCellZippedAcyclicIterator<HeapCellIter> {
    i1: HeapCellIter,
    i2: HeapCellIter,
    seen: HashSet<(Addr, Addr)>
}

impl<HeapCellIter: MutStackHeapCellIterator> HeapCellZippedAcyclicIterator<HeapCellIter>
{
    pub fn new(i1: HeapCellIter, i2: HeapCellIter) -> Self {
        HeapCellZippedAcyclicIterator { i1, i2, seen: HashSet::new() }
    }
}

impl<HeapCellIter> Iterator for HeapCellZippedAcyclicIterator<HeapCellIter>
    where HeapCellIter: Iterator<Item=HeapCellValue>
                      + MutStackHeapCellIterator
{
    type Item = (HeapCellValue, HeapCellValue);

    fn next(&mut self) -> Option<Self::Item> {
        while let (Some(a1), Some(a2)) = (self.i1.stack().pop(), self.i2.stack().pop()) {
            if self.seen.contains(&(a1.clone(), a2.clone())) {
                continue;
            } else {
                self.i1.stack().push(a1.clone());
                self.i2.stack().push(a2.clone());
                self.seen.insert((a1, a2));

                break;
            }
        }

        if let (Some(v1), Some(v2)) = (self.i1.next(), self.i2.next()) {
            Some((v1, v2))
        } else {
            None
        }
    }
}
<commit_msg>simplify heap_iter.rs<commit_after>use prolog::ast::*;
use prolog::machine::machine_state::MachineState;

use std::collections::HashSet;
use std::vec::Vec;

pub struct HeapCellPreOrderIterator<'a> {
    machine_st: &'a MachineState,
    state_stack: Vec<Addr>
}

impl<'a> HeapCellPreOrderIterator<'a> {
    pub fn new(machine_st: &'a MachineState, a: Addr) -> Self
    {
        HeapCellPreOrderIterator {
            machine_st, state_stack: vec![a]
        }
    }

    fn follow_heap(&mut self, h: usize) -> Addr
    {
        match &self.machine_st.heap[h] {
            &HeapCellValue::NamedStr(arity, _, _) => {
                for idx in (1 .. arity + 1).rev() {
                    self.state_stack.push(Addr::HeapCell(h + idx));
                }

                Addr::HeapCell(h)
            },
            &HeapCellValue::Addr(ref a) =>
                self.follow(a.clone())
        }
    }

    // called under the assumption that the location at r is about to
    // be visited, and so any follow up states need to be added to
    // state_stack. returns the dereferenced Addr from Ref.
    fn follow(&mut self, addr: Addr) -> Addr
    {
        let da = self.machine_st.store(self.machine_st.deref(addr));

        match &da {
            &Addr::Con(_) => da,
            &Addr::Lis(a) => {
                self.state_stack.push(Addr::HeapCell(a + 1));
                self.state_stack.push(Addr::HeapCell(a));

                da
            },
            &Addr::HeapCell(_) | &Addr::StackCell(_, _) =>
                da,
            &Addr::Str(s) =>
                self.follow_heap(s) // record terms of structure.
        }
    }
}

impl<'a> Iterator for HeapCellPreOrderIterator<'a> {
    type Item = HeapCellValue;

    fn next(&mut self) -> Option<Self::Item> {
        if let Some(a) = self.state_stack.pop() {
            match self.follow(a) {
                Addr::HeapCell(h) => Some(self.machine_st.heap[h].clone()),
                Addr::StackCell(fr, sc) => {
                    let heap_val = HeapCellValue::Addr(self.machine_st.and_stack[fr][sc].clone());
                    Some(heap_val)
                },
                da => Some(HeapCellValue::Addr(da))
            }
        } else {
            None
        }
    }
}

pub struct HeapCellPostOrderIterator<'a> {
    pre_iter:     HeapCellPreOrderIterator<'a>,
    parent_stack: Vec<(usize, HeapCellValue)> // number of children, parent node.
}

impl<'a> HeapCellPostOrderIterator<'a> {
    pub fn new(pre_iter: HeapCellPreOrderIterator<'a>) -> Self {
        HeapCellPostOrderIterator {
            pre_iter,
            parent_stack: vec![]
        }
    }
}

impl<'a> Iterator for HeapCellPostOrderIterator<'a> {
    type Item = HeapCellValue;

    fn next(&mut self) -> Option<Self::Item> {
        loop {
            if let Some((child_count, node)) = self.parent_stack.pop() {
                if child_count == 0 {
                    return Some(node);
                }

                self.parent_stack.push((child_count - 1, node));
            }

            if let Some(item) = self.pre_iter.next() {
                match item {
                    HeapCellValue::NamedStr(arity, name, fix) =>
                        self.parent_stack.push((arity, HeapCellValue::NamedStr(arity, name, fix))),
                    HeapCellValue::Addr(Addr::Lis(a)) =>
                        self.parent_stack.push((2, HeapCellValue::Addr(Addr::Lis(a)))),
                    child_node => {
                        return Some(child_node);
                    }
                }
            } else {
                return None;
            }
        }
    }
}

impl MachineState {
    pub fn post_order_iter<'a>(&'a self, a: Addr) -> HeapCellPostOrderIterator<'a> {
        HeapCellPostOrderIterator::new(HeapCellPreOrderIterator::new(self, a))
    }

    pub fn acyclic_pre_order_iter<'a>(&'a self, a: Addr)
                                      -> HeapCellAcyclicIterator<HeapCellPreOrderIterator<'a>>
    {
        HeapCellAcyclicIterator::new(HeapCellPreOrderIterator::new(self, a))
    }

    pub fn zipped_acyclic_pre_order_iter<'a>(&'a self, a1: Addr, a2: Addr)
                                             -> HeapCellZippedAcyclicIterator<HeapCellPreOrderIterator<'a>>
    {
        HeapCellZippedAcyclicIterator::new(HeapCellPreOrderIterator::new(self, a1),
                                           HeapCellPreOrderIterator::new(self, a2))
    }
}

pub trait MutStackHeapCellIterator {
    fn stack(&mut self) -> &mut Vec<Addr>;
}

impl<'a> MutStackHeapCellIterator for HeapCellPreOrderIterator<'a> {
    fn stack(&mut self) -> &mut Vec<Addr> {
        &mut self.state_stack
    }
}

pub struct HeapCellAcyclicIterator<HeapCellIter> {
    iter: HeapCellIter,
    seen: HashSet<Addr>
}

impl<HeapCellIter: MutStackHeapCellIterator> HeapCellAcyclicIterator<HeapCellIter>
{
    pub fn new(iter: HeapCellIter) -> Self {
        HeapCellAcyclicIterator { iter, seen: HashSet::new() }
    }
}

impl<HeapCellIter> Iterator for HeapCellAcyclicIterator<HeapCellIter>
    where HeapCellIter: Iterator<Item=HeapCellValue>
                      + MutStackHeapCellIterator
{
    type Item = HeapCellValue;

    fn next(&mut self) -> Option<Self::Item> {
        while let Some(addr) = self.iter.stack().pop() {
            if !self.seen.contains(&addr) {
                self.iter.stack().push(addr.clone());
                self.seen.insert(addr);
                break;
            }
        }

        self.iter.next()
    }
}

pub struct HeapCellZippedAcyclicIterator<HeapCellIter> {
    i1: HeapCellIter,
    i2: HeapCellIter,
    seen: HashSet<(Addr, Addr)>
}

impl<HeapCellIter: MutStackHeapCellIterator> HeapCellZippedAcyclicIterator<HeapCellIter>
{
    pub fn new(i1: HeapCellIter, i2: HeapCellIter) -> Self {
        HeapCellZippedAcyclicIterator { i1, i2, seen: HashSet::new() }
    }
}

impl<HeapCellIter> Iterator for HeapCellZippedAcyclicIterator<HeapCellIter>
    where HeapCellIter: Iterator<Item=HeapCellValue>
                      + MutStackHeapCellIterator
{
    type Item = (HeapCellValue, HeapCellValue);

    fn next(&mut self) -> Option<Self::Item> {
        while let (Some(a1), Some(a2)) = (self.i1.stack().pop(), self.i2.stack().pop()) {
            if !self.seen.contains(&(a1.clone(), a2.clone())) {
                self.i1.stack().push(a1.clone());
                self.i2.stack().push(a2.clone());
                self.seen.insert((a1, a2));

                break;
            }
        }

        if let (Some(v1), Some(v2)) = (self.i1.next(), self.i2.next()) {
            Some((v1, v2))
        } else {
            None
        }
    }
}
<|endoftext|>


<commit_before>use Application;
use ffi;
use gio::ApplicationFlags;
use glib::object::IsA;
use glib::translate::*;
use rt;
use glib;
use glib_ffi;

impl Application {
    #[cfg(feature = "v3_6")]
    fn new(application_id: Option<&str>, flags: ApplicationFlags) -> Result<Application, glib::BoolError> {
        skip_assert_initialized!();
        try!(rt::init());
        unsafe {
            Option::from_glib_full(
                ffi::gtk_application_new(application_id.to_glib_none().0, flags.to_glib()))
                .ok_or(glib::BoolError("Failed to create application"))
        }
    }

    #[cfg(not(feature = "v3_6"))]
    fn new(application_id: &str, flags: ApplicationFlags) -> Result<Application, glib::BoolError> {
        skip_assert_initialized!();
        try!(rt::init());
        unsafe {
            Option::from_glib_full(
                ffi::gtk_application_new(application_id.to_glib_none().0, flags.to_glib()))
                .ok_or(glib::BoolError("Failed to create application"))
        }
    }
}
<commit_msg>Change gtk::Application::new parameter to use Into<Option<&str>><commit_after>use Application;
use ffi;
use gio::ApplicationFlags;
use glib::object::IsA;
use glib::translate::*;
use rt;
use glib;
use glib_ffi;

impl Application {
    #[cfg(feature = "v3_6")]
    pub fn new<'a, I: Into<Option<&'a str>>>(application_id: I, flags: ApplicationFlags) -> Result<Application, glib::BoolError> {
        skip_assert_initialized!();
        try!(rt::init());
        unsafe {
            Option::from_glib_full(
                ffi::gtk_application_new(application_id.into().to_glib_none().0, flags.to_glib()))
                .ok_or(glib::BoolError("Failed to create application"))
        }
    }

    #[cfg(not(feature = "v3_6"))]
    pub fn new(application_id: &str, flags: ApplicationFlags) -> Result<Application, glib::BoolError> {
        skip_assert_initialized!();
        try!(rt::init());
        unsafe {
            Option::from_glib_full(
                ffi::gtk_application_new(application_id.to_glib_none().0, flags.to_glib()))
                .ok_or(glib::BoolError("Failed to create application"))
        }
    }
}
<|endoftext|>


<commit_before>// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

use super::{super::DirectEvaluatorInput, ApiEvaluatorError, API_CATEGORY};
use crate::{
    configuration::EvaluatorArgs,
    evaluator::{EvaluationResult, Evaluator},
    evaluators::EvaluatorType,
};
use anyhow::Result;
use aptos_rest_client::{aptos_api_types::TransactionData, Client as AptosRestClient};
use clap::Parser;
use poem_openapi::Object as PoemObject;
use serde::{Deserialize, Serialize};
use std::cmp::{max, min};

const TRANSACTIONS_ENDPOINT: &str = "/transactions/by_version";

#[derive(Clone, Debug, Deserialize, Parser, PoemObject, Serialize)]
pub struct TransactionAvailabilityEvaluatorArgs {}

#[derive(Debug)]
pub struct TransactionAvailabilityEvaluator {
    #[allow(dead_code)]
    args: TransactionAvailabilityEvaluatorArgs,
}

impl TransactionAvailabilityEvaluator {
    pub fn new(args: TransactionAvailabilityEvaluatorArgs) -> Self {
        Self { args }
    }

    /// Fetch a transaction by version and return it.
    async fn get_transaction_by_version(
        client: &AptosRestClient,
        version: u64,
        node_name: &str,
    ) -> Result<TransactionData, ApiEvaluatorError> {
        Ok(client
            .get_transaction_by_version_bcs(version)
            .await
            .map_err(|e| {
                ApiEvaluatorError::EndpointError(
                    TRANSACTIONS_ENDPOINT.to_string(),
                    anyhow::Error::from(e).context(format!(
                        "The {} node API failed to return the requested transaction at version: {}",
                        node_name, version
                    )),
                )
            })?
            .into_inner())
    }

    /// Helper to get the accumulator root hash from an on chain transaction
    /// as returned by the API.
    fn unwrap_accumulator_root_hash(
        transaction_data: &TransactionData,
    ) -> Result<&aptos_crypto::HashValue, ApiEvaluatorError> {
        match transaction_data {
            TransactionData::OnChain(on_chain) => Ok(&on_chain.accumulator_root_hash),
            wildcard => Err(ApiEvaluatorError::EndpointError(
                TRANSACTIONS_ENDPOINT.to_string(),
                anyhow::anyhow!(
                    "The API unexpectedly returned a transaction that was not an on-chain transaction: {:?}",
                    wildcard
                ),
            ))
        }
    }
}

#[async_trait::async_trait]
impl Evaluator for TransactionAvailabilityEvaluator {
    type Input = DirectEvaluatorInput;
    type Error = ApiEvaluatorError;

    /// Assert that the target node can produce the same transaction that the
    /// baseline produced after a delay. We confirm that the transactions are
    /// same by looking at the version.
    async fn evaluate(&self, input: &Self::Input) -> Result<Vec<EvaluationResult>, Self::Error> {
        let oldest_baseline_version = input.baseline_index_response.oldest_ledger_version.0;
        let oldest_target_version = input.target_index_response.oldest_ledger_version.0;
        let latest_baseline_version = input.baseline_index_response.ledger_version.0;
        let latest_target_version = input.target_index_response.ledger_version.0;

        // Get the oldest ledger version between the two nodes.
        let oldest_shared_version = max(oldest_baseline_version, oldest_target_version);

        // Get the least up to date latest ledger version between the two nodes.
        let latest_shared_version = min(latest_baseline_version, latest_target_version);

        // Ensure that there is a window between the oldest shared version and
        // latest shared version. If there is not, it will not be possible to
        // pull a transaction that both nodes have.
        if oldest_shared_version > latest_shared_version {
            return Ok(vec![self.build_evaluation_result(
                "Unable to pull transaction from both nodes".to_string(),
                0,
                format!(
                    "We were unable to find a ledger version window between \
                        the baseline and target nodes. The oldest and latest \
                        ledger versions on the baseline node are {} and {}. \
                        The oldest and latest ledger versions on the target \
                        node are {} and {}. This means your API cannot return \
                        a transaction that the baseline has for us to verify. \
                        Likely this means your node is too out of sync with \
                        the network, but it could also indicate an \
                        over-aggressive pruner.",
                    oldest_baseline_version,
                    latest_baseline_version,
                    oldest_target_version,
                    latest_target_version,
                ),
            )]);
        }

        // We've asserted that both nodes are sufficiently up to date relative
        // to each other, we should be able to pull the same transaction from
        // both nodes.

        let baseline_client = input
            .baseline_node_information
            .node_address
            .get_api_client(std::time::Duration::from_secs(4));

        let latest_baseline_transaction =
            Self::get_transaction_by_version(&baseline_client, latest_shared_version, "baseline")
                .await?;

        let latest_baseline_accumulator_root_hash =
            Self::unwrap_accumulator_root_hash(&latest_baseline_transaction)?;

        let target_client = AptosRestClient::new(input.target_node_address.get_api_url());
        let evaluation =
            match Self::get_transaction_by_version(&target_client, latest_shared_version, "target")
                .await
            {
                Ok(latest_target_transaction) => {
                    match Self::unwrap_accumulator_root_hash(&latest_target_transaction) {
                        Ok(latest_target_accumulator_root_hash) => {
                            if latest_baseline_accumulator_root_hash
                                == latest_target_accumulator_root_hash
                            {
                                self.build_evaluation_result(
                                    "Target node produced valid recent transaction".to_string(),
                                    100,
                                    format!(
                                        "We were able to pull the same transaction (version: {}) \
                                    from both your node and the baseline node. Great! This \
                                    implies that your node is keeping up with other nodes \
                                    in the network and returning valid transaction data.",
                                        latest_shared_version,
                                    ),
                                )
                            } else {
                                self.build_evaluation_result(
                                    "Target node produced recent transaction, but it was invalid"
                                        .to_string(),
                                    0,
                                    format!(
                                        "We were able to pull the same transaction (version: {}) \
                                    from both your node and the baseline node. However, the \
                                    transaction was invalid compared to the baseline as the \
                                    accumulator root hash of the transaction ({}) was different \
                                    compared to the baseline ({}).",
                                        latest_shared_version,
                                        latest_target_accumulator_root_hash,
                                        latest_baseline_accumulator_root_hash,
                                    ),
                                )
                            }
                        }
                        Err(error) => self.build_evaluation_result(
                            "Target node produced recent transaction, but it was missing metadata"
                                .to_string(),
                            10,
                            format!(
                                "We were able to pull the same transaction (version: {}) \
                            from both your node and the baseline node. However, the \
                            the transaction was missing metadata such as the version, \
                            accumulator root hash, etc. Error: {}",
                                latest_shared_version, error,
                            ),
                        ),
                    }
                }
                Err(error) => self.build_evaluation_result(
                    "Target node failed to produce transaction".to_string(),
                    25,
                    format!(
                        "The target node claims it has transactions between versions {} and {}, \
                    but it was unable to return the transaction with version {}. This implies \
                    something is wrong with your node's API. Error: {}",
                        oldest_target_version, latest_target_version, latest_shared_version, error,
                    ),
                ),
            };

        Ok(vec![evaluation])
    }

    fn get_category_name() -> String {
        API_CATEGORY.to_string()
    }

    fn get_evaluator_name() -> String {
        "transaction_availability".to_string()
    }

    fn from_evaluator_args(evaluator_args: &EvaluatorArgs) -> Result<Self> {
        Ok(Self::new(
            evaluator_args.transaction_availability_args.clone(),
        ))
    }

    fn evaluator_type_from_evaluator_args(evaluator_args: &EvaluatorArgs) -> Result<EvaluatorType> {
        Ok(EvaluatorType::Api(Box::new(Self::from_evaluator_args(
            evaluator_args,
        )?)))
    }
}
<commit_msg>[NHC] Use transaction from middle of available version range in API availabilty checker (#3917)<commit_after>// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

use super::{super::DirectEvaluatorInput, ApiEvaluatorError, API_CATEGORY};
use crate::{
    configuration::EvaluatorArgs,
    evaluator::{EvaluationResult, Evaluator},
    evaluators::EvaluatorType,
};
use anyhow::Result;
use aptos_rest_client::{aptos_api_types::TransactionData, Client as AptosRestClient};
use clap::Parser;
use poem_openapi::Object as PoemObject;
use serde::{Deserialize, Serialize};
use std::cmp::{max, min};

const TRANSACTIONS_ENDPOINT: &str = "/transactions/by_version";

#[derive(Clone, Debug, Deserialize, Parser, PoemObject, Serialize)]
pub struct TransactionAvailabilityEvaluatorArgs {}

#[derive(Debug)]
pub struct TransactionAvailabilityEvaluator {
    #[allow(dead_code)]
    args: TransactionAvailabilityEvaluatorArgs,
}

impl TransactionAvailabilityEvaluator {
    pub fn new(args: TransactionAvailabilityEvaluatorArgs) -> Self {
        Self { args }
    }

    /// Fetch a transaction by version and return it.
    async fn get_transaction_by_version(
        client: &AptosRestClient,
        version: u64,
        node_name: &str,
    ) -> Result<TransactionData, ApiEvaluatorError> {
        Ok(client
            .get_transaction_by_version_bcs(version)
            .await
            .map_err(|e| {
                ApiEvaluatorError::EndpointError(
                    TRANSACTIONS_ENDPOINT.to_string(),
                    anyhow::Error::from(e).context(format!(
                        "The {} node API failed to return the requested transaction at version: {}",
                        node_name, version
                    )),
                )
            })?
            .into_inner())
    }

    /// Helper to get the accumulator root hash from an on chain transaction
    /// as returned by the API.
    fn unwrap_accumulator_root_hash(
        transaction_data: &TransactionData,
    ) -> Result<&aptos_crypto::HashValue, ApiEvaluatorError> {
        match transaction_data {
            TransactionData::OnChain(on_chain) => Ok(&on_chain.accumulator_root_hash),
            wildcard => Err(ApiEvaluatorError::EndpointError(
                TRANSACTIONS_ENDPOINT.to_string(),
                anyhow::anyhow!(
                    "The API unexpectedly returned a transaction that was not an on-chain transaction: {:?}",
                    wildcard
                ),
            ))
        }
    }
}

#[async_trait::async_trait]
impl Evaluator for TransactionAvailabilityEvaluator {
    type Input = DirectEvaluatorInput;
    type Error = ApiEvaluatorError;

    /// Assert that the target node can produce the same transaction that the
    /// baseline produced after a delay. We confirm that the transactions are
    /// same by looking at the version.
    async fn evaluate(&self, input: &Self::Input) -> Result<Vec<EvaluationResult>, Self::Error> {
        let oldest_baseline_version = input.baseline_index_response.oldest_ledger_version.0;
        let oldest_target_version = input.target_index_response.oldest_ledger_version.0;
        let latest_baseline_version = input.baseline_index_response.ledger_version.0;
        let latest_target_version = input.target_index_response.ledger_version.0;

        // Get the oldest ledger version between the two nodes.
        let oldest_shared_version = max(oldest_baseline_version, oldest_target_version);

        // Get the least up to date latest ledger version between the two nodes.
        let latest_shared_version = min(latest_baseline_version, latest_target_version);

        // Ensure that there is a window between the oldest shared version and
        // latest shared version. If there is not, it will not be possible to
        // pull a transaction that both nodes have.
        if oldest_shared_version > latest_shared_version {
            return Ok(vec![self.build_evaluation_result(
                "Unable to pull transaction from both nodes".to_string(),
                0,
                format!(
                    "We were unable to find a ledger version window between \
                        the baseline and target nodes. The oldest and latest \
                        ledger versions on the baseline node are {} and {}. \
                        The oldest and latest ledger versions on the target \
                        node are {} and {}. This means your API cannot return \
                        a transaction that the baseline has for us to verify. \
                        Likely this means your node is too out of sync with \
                        the network, but it could also indicate an \
                        over-aggressive pruner.",
                    oldest_baseline_version,
                    latest_baseline_version,
                    oldest_target_version,
                    latest_target_version,
                ),
            )]);
        }

        // Select a version in the middle of shared oldest and latest version.
        let middle_shared_version =
            (oldest_shared_version.saturating_add(latest_shared_version)) / 2;

        // We've asserted that both nodes are sufficiently up to date relative
        // to each other, we should be able to pull the same transaction from
        // both nodes.

        let baseline_client = input
            .baseline_node_information
            .node_address
            .get_api_client(std::time::Duration::from_secs(4));

        let middle_baseline_transaction =
            Self::get_transaction_by_version(&baseline_client, middle_shared_version, "baseline")
                .await?;
        let middle_baseline_accumulator_root_hash =
            Self::unwrap_accumulator_root_hash(&middle_baseline_transaction)?;

        let target_client = AptosRestClient::new(input.target_node_address.get_api_url());
        let evaluation =
            match Self::get_transaction_by_version(&target_client, middle_shared_version, "latest")
                .await
            {
                Ok(middle_target_transaction) => {
                    match Self::unwrap_accumulator_root_hash(&middle_target_transaction) {
                        Ok(middle_target_accumulator_root_hash) => {
                            if middle_baseline_accumulator_root_hash
                                == middle_target_accumulator_root_hash
                            {
                                self.build_evaluation_result(
                                    "Target node produced valid recent transaction".to_string(),
                                    100,
                                    format!(
                                        "We were able to pull the same transaction (version: {}) \
                                    from both your node and the baseline node. Great! This \
                                    implies that your node is keeping up with other nodes \
                                    in the network and returning valid transaction data.",
                                        middle_shared_version,
                                    ),
                                )
                            } else {
                                self.build_evaluation_result(
                                    "Target node produced recent transaction, but it was invalid"
                                        .to_string(),
                                    0,
                                    format!(
                                        "We were able to pull the same transaction (version: {}) \
                                    from both your node and the baseline node. However, the \
                                    transaction was invalid compared to the baseline as the \
                                    accumulator root hash of the transaction ({}) was different \
                                    compared to the baseline ({}).",
                                        middle_shared_version,
                                        middle_target_accumulator_root_hash,
                                        middle_baseline_accumulator_root_hash,
                                    ),
                                )
                            }
                        }
                        Err(error) => self.build_evaluation_result(
                            "Target node produced recent transaction, but it was missing metadata"
                                .to_string(),
                            10,
                            format!(
                                "We were able to pull the same transaction (version: {}) \
                            from both your node and the baseline node. However, the \
                            the transaction was missing metadata such as the version, \
                            accumulator root hash, etc. Error: {}",
                                middle_shared_version, error,
                            ),
                        ),
                    }
                }
                Err(error) => self.build_evaluation_result(
                    "Target node failed to produce transaction".to_string(),
                    25,
                    format!(
                        "The target node claims it has transactions between versions {} and {}, \
                    but it was unable to return the transaction with version {}. This implies \
                    something is wrong with your node's API. Error: {}",
                        oldest_target_version, latest_target_version, middle_shared_version, error,
                    ),
                ),
            };

        Ok(vec![evaluation])
    }

    fn get_category_name() -> String {
        API_CATEGORY.to_string()
    }

    fn get_evaluator_name() -> String {
        "transaction_availability".to_string()
    }

    fn from_evaluator_args(evaluator_args: &EvaluatorArgs) -> Result<Self> {
        Ok(Self::new(
            evaluator_args.transaction_availability_args.clone(),
        ))
    }

    fn evaluator_type_from_evaluator_args(evaluator_args: &EvaluatorArgs) -> Result<EvaluatorType> {
        Ok(EvaluatorType::Api(Box::new(Self::from_evaluator_args(
            evaluator_args,
        )?)))
    }
}
<|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.

//! Handling messages received from P2P node network.
//!
//! Every message passes through three phases:
//!
//!   * `Vec<u8>`: raw bytes as received from the network
//!   * `SignedMessage`: integrity and signature of the message has been verified
//!   * `Message`: the message has been completely parsed and has correct structure
//!
//! Graphical representation of the message processing flow:
//!
//! ```text
//! +---------+             +---------------+                  +----------+
//! | Vec<u8> |--(verify)-->| SignedMessage |--(deserialize)-->| Message |-->(handle)
//! +---------+     |       +---------------+        |         +----------+
//!                 |                                |
//!                 V                                V
//!              (drop)                           (drop)
//!
//! ```
//!
//! # Examples
//!
//! The procedure of creating a new signed message is as follows.
//!
//! ```
//! use exonum::{
//!     crypto::{self, Hash},
//!     helpers::Height,
//!     messages::{Status, Verified},
//! };
//!
//! # fn send<T>(_: T) {}
//! let keypair = crypto::gen_keypair();
//! // For example, get some `Status` message.
//! let payload = Status {
//!     height: Height(15),
//!     last_hash: Hash::zero(),
//!     pool_size: 12,
//! };
//! // Sign the message with some keypair to get a trusted "Status" message.
//! let signed_payload = Verified::from_value(payload, keypair.0, &keypair.1);
//! // Further, convert the trusted message into a raw signed message and send
//! // it through the network.
//! let raw_signed_message = signed_payload.into_raw();
//! send(raw_signed_message);
//! ```
//!
//! The procedure of verification of a signed message is as follows:
//!
//! ```
//! use exonum::{
//!     crypto::{self, Hash},
//!     helpers::Height,
//!     messages::{Status, Verified, SignedMessage, ExonumMessage},
//! };
//!
//! # fn get_signed_message() -> SignedMessage {
//! #   let keypair = crypto::gen_keypair();
//! #   let payload = Status {
//! #       height: Height(15),
//! #       last_hash: Hash::zero(),
//! #       pool_size: 0,
//! #   };
//! #   Verified::from_value(payload, keypair.0, &keypair.1).into_raw()
//! # }
//! // Assume you have some signed message.
//! let raw: SignedMessage = get_signed_message();
//! // You know that this is a type of `ExonumMessage`, so you can
//! // verify its signature and convert it into `ExonumMessage`.
//! let verified = raw.into_verified::<ExonumMessage>().expect("verification failed");
//! // Further, check whether it is a `Status` message.
//! if let ExonumMessage::Status(ref status) = verified.payload() {
//!     // ...
//! }
//! ```
//!
//!

pub use self::{signed::Verified, types::*};
pub use exonum_merkledb::BinaryValue;

use exonum_merkledb::ObjectHash;

use std::borrow::Cow;

use crate::{
    crypto::{Hash, PublicKey, SecretKey, PUBLIC_KEY_LENGTH, SIGNATURE_LENGTH},
    helpers::{Height, Round, ValidatorId},
};

#[macro_use]
mod macros;
mod signed;
#[cfg(test)]
mod tests;
mod types;

/// Lower bound on the size of the correct `SignedMessage`.
/// Size of message fields + protobuf overhead.
#[doc(hidden)]
pub const SIGNED_MESSAGE_MIN_SIZE: usize = PUBLIC_KEY_LENGTH + SIGNATURE_LENGTH + 8;

#[doc(hidden)]
pub const TX_RES_EMPTY_SIZE: usize = SIGNED_MESSAGE_MIN_SIZE + PUBLIC_KEY_LENGTH + 8;

/// When we add transaction to TransactionResponse message we will add some overhead
/// to the message size due to protobuf.
/// This is higher bound on this overhead.
/// Tx response message size <= TX_RES_EMPTY_SIZE + (tx1 size + TX_RES_PB_OVERHEAD_PAYLOAD) +
///                             + (tx2 size + TX_RES_PB_OVERHEAD_PAYLOAD) + ...
#[doc(hidden)]
pub const TX_RES_PB_OVERHEAD_PAYLOAD: usize = 8;

/// Service messages.
#[derive(Debug, Clone, PartialEq)]
pub enum Service {
    /// Transaction message.
    AnyTx(Verified<AnyTx>),
    /// Connect message.
    Connect(Verified<Connect>),
    /// Status message.
    Status(Verified<Status>),
}

impl Service {
    fn as_raw(&self) -> &SignedMessage {
        match self {
            Service::AnyTx(ref msg) => msg.as_raw(),
            Service::Connect(ref msg) => msg.as_raw(),
            Service::Status(ref msg) => msg.as_raw(),
        }
    }
}

/// Consensus messages.
#[derive(Debug, Clone, PartialEq)]
pub enum Consensus {
    /// `Precommit` message.
    Precommit(Verified<Precommit>),
    /// `Propose` message.
    Propose(Verified<Propose>),
    /// `Prevote` message.
    Prevote(Verified<Prevote>),
}

impl Consensus {
    fn as_raw(&self) -> &SignedMessage {
        match self {
            Consensus::Precommit(ref msg) => msg.as_raw(),
            Consensus::Propose(ref msg) => msg.as_raw(),
            Consensus::Prevote(ref msg) => msg.as_raw(),
        }
    }
}

/// Response messages.
#[derive(Debug, Clone, PartialEq)]
pub enum Responses {
    /// Transactions response message.
    TransactionsResponse(Verified<TransactionsResponse>),
    /// Block response message.
    BlockResponse(Verified<BlockResponse>),
}

impl Responses {
    fn as_raw(&self) -> &SignedMessage {
        match self {
            Responses::TransactionsResponse(ref msg) => msg.as_raw(),
            Responses::BlockResponse(ref msg) => msg.as_raw(),
        }
    }
}

impl From<Verified<TransactionsResponse>> for Responses {
    fn from(msg: Verified<TransactionsResponse>) -> Self {
        Responses::TransactionsResponse(msg)
    }
}

impl From<Verified<BlockResponse>> for Responses {
    fn from(msg: Verified<BlockResponse>) -> Self {
        Responses::BlockResponse(msg)
    }
}

/// Request messages.
#[derive(Debug, Clone, PartialEq)]
pub enum Requests {
    /// Propose request message.
    ProposeRequest(Verified<ProposeRequest>),
    /// Transactions request message.
    TransactionsRequest(Verified<TransactionsRequest>),
    /// Prevotes request message.
    PrevotesRequest(Verified<PrevotesRequest>),
    /// Peers request message.
    PeersRequest(Verified<PeersRequest>),
    /// Block request message.
    BlockRequest(Verified<BlockRequest>),
    /// Request of uncommitted transactions.
    PoolTransactionsRequest(Verified<PoolTransactionsRequest>),
}

impl Requests {
    fn as_raw(&self) -> &SignedMessage {
        match self {
            Requests::ProposeRequest(ref msg) => msg.as_raw(),
            Requests::TransactionsRequest(ref msg) => msg.as_raw(),
            Requests::PrevotesRequest(ref msg) => msg.as_raw(),
            Requests::PeersRequest(ref msg) => msg.as_raw(),
            Requests::BlockRequest(ref msg) => msg.as_raw(),
            Requests::PoolTransactionsRequest(ref msg) => msg.as_raw(),
        }
    }
}

/// Representation of the Exonum message which is divided into categories.
#[derive(Debug, Clone, PartialEq)]
pub enum Message {
    /// Service messages.
    Service(Service),
    /// Consensus messages.
    Consensus(Consensus),
    /// Responses messages.
    Responses(Responses),
    /// Requests messages.
    Requests(Requests),
}

impl Message {
    /// Creates a new signed Exonum message from the given value.
    pub fn from_value<T: Into<ExonumMessage>>(
        message: T,
        author: PublicKey,
        secret_key: &SecretKey,
    ) -> Self {
        Self::from(Verified::from_value(message.into(), author, secret_key))
    }

    /// Deserialize message from signed message.
    pub fn from_signed(signed: SignedMessage) -> Result<Self, failure::Error> {
        signed.into_verified::<ExonumMessage>().map(From::from)
    }

    /// Checks buffer and returns instance of `Message`.
    pub fn from_raw_buffer(buffer: Vec<u8>) -> Result<Self, failure::Error> {
        SignedMessage::from_bytes(buffer.into()).and_then(Self::from_signed)
    }

    /// Get inner SignedMessage.
    pub fn as_raw(&self) -> &SignedMessage {
        match self {
            Message::Service(ref msg) => msg.as_raw(),
            Message::Consensus(ref msg) => msg.as_raw(),
            Message::Requests(ref msg) => msg.as_raw(),
            Message::Responses(ref msg) => msg.as_raw(),
        }
    }
}

impl PartialEq<SignedMessage> for Message {
    fn eq(&self, other: &SignedMessage) -> bool {
        self.as_raw() == other
    }
}

macro_rules! impl_message_from_verified {
    ( $($concrete:ident: $category:ident),* ) => {
        $(
            impl From<Verified<$concrete>> for Message {
                fn from(msg: Verified<$concrete>) -> Self {
                    Message::$category($category::$concrete(msg))
                }
            }

            impl std::convert::TryFrom<Message> for Verified<$concrete> {
                type Error = failure::Error;

                fn try_from(msg: Message) -> Result<Self, Self::Error> {
                    if let Message::$category($category::$concrete(msg)) = msg {
                        Ok(msg)
                    } else {
                        Err(failure::format_err!(
                            "Given message is not a {}::{}",
                            stringify!($category),
                            stringify!($concrete)
                        ))
                    }
                }
            }
        )*

        impl From<Verified<ExonumMessage>> for Message {
            fn from(msg: Verified<ExonumMessage>) -> Self {
                let raw = msg.raw;
                match msg.inner {
                    $(
                        ExonumMessage::$concrete(inner) => {
                            let inner = Verified::<$concrete> { raw, inner };
                            Self::from(inner)
                        }
                    )*
                }
            }
        }
    };
}

impl_message_from_verified! {
    AnyTx: Service,
    Connect: Service,
    Status: Service,
    Precommit: Consensus,
    Prevote: Consensus,
    Propose: Consensus,
    BlockResponse: Responses,
    TransactionsResponse: Responses,
    BlockRequest: Requests,
    PeersRequest: Requests,
    PrevotesRequest: Requests,
    ProposeRequest: Requests,
    TransactionsRequest: Requests,
    PoolTransactionsRequest: Requests
}

impl Requests {
    /// Returns public key of the message recipient.
    pub fn to(&self) -> PublicKey {
        match *self {
            Requests::ProposeRequest(ref msg) => msg.payload().to,
            Requests::TransactionsRequest(ref msg) => msg.payload().to,
            Requests::PrevotesRequest(ref msg) => msg.payload().to,
            Requests::PeersRequest(ref msg) => msg.payload().to,
            Requests::BlockRequest(ref msg) => msg.payload().to,
            Requests::PoolTransactionsRequest(ref msg) => msg.payload().to,
        }
    }

    /// Returns author public key of the message sender.
    pub fn author(&self) -> PublicKey {
        match *self {
            Requests::ProposeRequest(ref msg) => msg.author(),
            Requests::TransactionsRequest(ref msg) => msg.author(),
            Requests::PrevotesRequest(ref msg) => msg.author(),
            Requests::PeersRequest(ref msg) => msg.author(),
            Requests::BlockRequest(ref msg) => msg.author(),
            Requests::PoolTransactionsRequest(ref msg) => msg.author(),
        }
    }
}

impl Consensus {
    /// Returns author public key of the message sender.
    pub fn author(&self) -> PublicKey {
        match *self {
            Consensus::Propose(ref msg) => msg.author(),
            Consensus::Prevote(ref msg) => msg.author(),
            Consensus::Precommit(ref msg) => msg.author(),
        }
    }

    /// Returns validator id of the message sender.
    pub fn validator(&self) -> ValidatorId {
        match *self {
            Consensus::Propose(ref msg) => msg.payload().validator(),
            Consensus::Prevote(ref msg) => msg.payload().validator(),
            Consensus::Precommit(ref msg) => msg.payload().validator(),
        }
    }

    /// Returns height of the message.
    pub fn height(&self) -> Height {
        match *self {
            Consensus::Propose(ref msg) => msg.payload().height(),
            Consensus::Prevote(ref msg) => msg.payload().height(),
            Consensus::Precommit(ref msg) => msg.payload().height(),
        }
    }

    /// Returns round of the message.
    pub fn round(&self) -> Round {
        match *self {
            Consensus::Propose(ref msg) => msg.payload().round(),
            Consensus::Prevote(ref msg) => msg.payload().round(),
            Consensus::Precommit(ref msg) => msg.payload().round(),
        }
    }
}

impl BinaryValue for Message {
    fn to_bytes(&self) -> Vec<u8> {
        self.as_raw().to_bytes()
    }

    fn from_bytes(value: Cow<'_, [u8]>) -> Result<Self, failure::Error> {
        let message = SignedMessage::from_bytes(value)?;
        Self::from_signed(message)
    }
}

impl ObjectHash for Message {
    fn object_hash(&self) -> Hash {
        self.as_raw().object_hash()
    }
}
<commit_msg>Fix module doc-comment in message module (#1599)<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.

//! Handling messages received from P2P node network.
//!
//! Every message passes through three phases:
//!
//!   * `Vec<u8>`: raw bytes as received from the network
//!   * `SignedMessage`: integrity and signature of the message has been verified
//!   * `Message`: the message has been completely parsed and has correct structure
//!
//! Graphical representation of the message processing flow:
//!
//! ```text
//! +---------+             +---------------+                  +----------+
//! | Vec<u8> |--(verify)-->| SignedMessage |--(deserialize)-->| Message  |-->(handle)
//! +---------+     |       +---------------+        |         +----------+
//!                 |                                |
//!                 V                                V
//!              (drop)                           (drop)
//!
//! ```
//!
//! # Examples
//!
//! The procedure of creating a new signed message is as follows.
//!
//! ```
//! use exonum::{
//!     crypto::{self, Hash},
//!     helpers::Height,
//!     messages::{Status, Verified},
//! };
//!
//! # fn send<T>(_: T) {}
//! let keypair = crypto::gen_keypair();
//! // For example, get some `Status` message.
//! let payload = Status {
//!     height: Height(15),
//!     last_hash: Hash::zero(),
//!     pool_size: 12,
//! };
//! // Sign the message with some keypair to get a trusted "Status" message.
//! let signed_payload = Verified::from_value(payload, keypair.0, &keypair.1);
//! // Further, convert the trusted message into a raw signed message and send
//! // it through the network.
//! let raw_signed_message = signed_payload.into_raw();
//! send(raw_signed_message);
//! ```
//!
//! The procedure of verification of a signed message is as follows:
//!
//! ```
//! use exonum::{
//!     crypto::{self, Hash},
//!     helpers::Height,
//!     messages::{Status, Verified, SignedMessage, ExonumMessage},
//! };
//!
//! # fn get_signed_message() -> SignedMessage {
//! #   let keypair = crypto::gen_keypair();
//! #   let payload = Status {
//! #       height: Height(15),
//! #       last_hash: Hash::zero(),
//! #       pool_size: 0,
//! #   };
//! #   Verified::from_value(payload, keypair.0, &keypair.1).into_raw()
//! # }
//! // Assume you have some signed message.
//! let raw: SignedMessage = get_signed_message();
//! // You know that this is a type of `ExonumMessage`, so you can
//! // verify its signature and convert it into `ExonumMessage`.
//! let verified = raw.into_verified::<ExonumMessage>().expect("verification failed");
//! // Further, check whether it is a `Status` message.
//! if let ExonumMessage::Status(ref status) = verified.payload() {
//!     // ...
//! }
//! ```
//!
//!

pub use self::{signed::Verified, types::*};
pub use exonum_merkledb::BinaryValue;

use exonum_merkledb::ObjectHash;

use std::borrow::Cow;

use crate::{
    crypto::{Hash, PublicKey, SecretKey, PUBLIC_KEY_LENGTH, SIGNATURE_LENGTH},
    helpers::{Height, Round, ValidatorId},
};

#[macro_use]
mod macros;
mod signed;
#[cfg(test)]
mod tests;
mod types;

/// Lower bound on the size of the correct `SignedMessage`.
/// Size of message fields + protobuf overhead.
#[doc(hidden)]
pub const SIGNED_MESSAGE_MIN_SIZE: usize = PUBLIC_KEY_LENGTH + SIGNATURE_LENGTH + 8;

#[doc(hidden)]
pub const TX_RES_EMPTY_SIZE: usize = SIGNED_MESSAGE_MIN_SIZE + PUBLIC_KEY_LENGTH + 8;

/// When we add transaction to TransactionResponse message we will add some overhead
/// to the message size due to protobuf.
/// This is higher bound on this overhead.
/// Tx response message size <= TX_RES_EMPTY_SIZE + (tx1 size + TX_RES_PB_OVERHEAD_PAYLOAD) +
///                             + (tx2 size + TX_RES_PB_OVERHEAD_PAYLOAD) + ...
#[doc(hidden)]
pub const TX_RES_PB_OVERHEAD_PAYLOAD: usize = 8;

/// Service messages.
#[derive(Debug, Clone, PartialEq)]
pub enum Service {
    /// Transaction message.
    AnyTx(Verified<AnyTx>),
    /// Connect message.
    Connect(Verified<Connect>),
    /// Status message.
    Status(Verified<Status>),
}

impl Service {
    fn as_raw(&self) -> &SignedMessage {
        match self {
            Service::AnyTx(ref msg) => msg.as_raw(),
            Service::Connect(ref msg) => msg.as_raw(),
            Service::Status(ref msg) => msg.as_raw(),
        }
    }
}

/// Consensus messages.
#[derive(Debug, Clone, PartialEq)]
pub enum Consensus {
    /// `Precommit` message.
    Precommit(Verified<Precommit>),
    /// `Propose` message.
    Propose(Verified<Propose>),
    /// `Prevote` message.
    Prevote(Verified<Prevote>),
}

impl Consensus {
    fn as_raw(&self) -> &SignedMessage {
        match self {
            Consensus::Precommit(ref msg) => msg.as_raw(),
            Consensus::Propose(ref msg) => msg.as_raw(),
            Consensus::Prevote(ref msg) => msg.as_raw(),
        }
    }
}

/// Response messages.
#[derive(Debug, Clone, PartialEq)]
pub enum Responses {
    /// Transactions response message.
    TransactionsResponse(Verified<TransactionsResponse>),
    /// Block response message.
    BlockResponse(Verified<BlockResponse>),
}

impl Responses {
    fn as_raw(&self) -> &SignedMessage {
        match self {
            Responses::TransactionsResponse(ref msg) => msg.as_raw(),
            Responses::BlockResponse(ref msg) => msg.as_raw(),
        }
    }
}

impl From<Verified<TransactionsResponse>> for Responses {
    fn from(msg: Verified<TransactionsResponse>) -> Self {
        Responses::TransactionsResponse(msg)
    }
}

impl From<Verified<BlockResponse>> for Responses {
    fn from(msg: Verified<BlockResponse>) -> Self {
        Responses::BlockResponse(msg)
    }
}

/// Request messages.
#[derive(Debug, Clone, PartialEq)]
pub enum Requests {
    /// Propose request message.
    ProposeRequest(Verified<ProposeRequest>),
    /// Transactions request message.
    TransactionsRequest(Verified<TransactionsRequest>),
    /// Prevotes request message.
    PrevotesRequest(Verified<PrevotesRequest>),
    /// Peers request message.
    PeersRequest(Verified<PeersRequest>),
    /// Block request message.
    BlockRequest(Verified<BlockRequest>),
    /// Request of uncommitted transactions.
    PoolTransactionsRequest(Verified<PoolTransactionsRequest>),
}

impl Requests {
    fn as_raw(&self) -> &SignedMessage {
        match self {
            Requests::ProposeRequest(ref msg) => msg.as_raw(),
            Requests::TransactionsRequest(ref msg) => msg.as_raw(),
            Requests::PrevotesRequest(ref msg) => msg.as_raw(),
            Requests::PeersRequest(ref msg) => msg.as_raw(),
            Requests::BlockRequest(ref msg) => msg.as_raw(),
            Requests::PoolTransactionsRequest(ref msg) => msg.as_raw(),
        }
    }
}

/// Representation of the Exonum message which is divided into categories.
#[derive(Debug, Clone, PartialEq)]
pub enum Message {
    /// Service messages.
    Service(Service),
    /// Consensus messages.
    Consensus(Consensus),
    /// Responses messages.
    Responses(Responses),
    /// Requests messages.
    Requests(Requests),
}

impl Message {
    /// Creates a new signed Exonum message from the given value.
    pub fn from_value<T: Into<ExonumMessage>>(
        message: T,
        author: PublicKey,
        secret_key: &SecretKey,
    ) -> Self {
        Self::from(Verified::from_value(message.into(), author, secret_key))
    }

    /// Deserialize message from signed message.
    pub fn from_signed(signed: SignedMessage) -> Result<Self, failure::Error> {
        signed.into_verified::<ExonumMessage>().map(From::from)
    }

    /// Checks buffer and returns instance of `Message`.
    pub fn from_raw_buffer(buffer: Vec<u8>) -> Result<Self, failure::Error> {
        SignedMessage::from_bytes(buffer.into()).and_then(Self::from_signed)
    }

    /// Get inner SignedMessage.
    pub fn as_raw(&self) -> &SignedMessage {
        match self {
            Message::Service(ref msg) => msg.as_raw(),
            Message::Consensus(ref msg) => msg.as_raw(),
            Message::Requests(ref msg) => msg.as_raw(),
            Message::Responses(ref msg) => msg.as_raw(),
        }
    }
}

impl PartialEq<SignedMessage> for Message {
    fn eq(&self, other: &SignedMessage) -> bool {
        self.as_raw() == other
    }
}

macro_rules! impl_message_from_verified {
    ( $($concrete:ident: $category:ident),* ) => {
        $(
            impl From<Verified<$concrete>> for Message {
                fn from(msg: Verified<$concrete>) -> Self {
                    Message::$category($category::$concrete(msg))
                }
            }

            impl std::convert::TryFrom<Message> for Verified<$concrete> {
                type Error = failure::Error;

                fn try_from(msg: Message) -> Result<Self, Self::Error> {
                    if let Message::$category($category::$concrete(msg)) = msg {
                        Ok(msg)
                    } else {
                        Err(failure::format_err!(
                            "Given message is not a {}::{}",
                            stringify!($category),
                            stringify!($concrete)
                        ))
                    }
                }
            }
        )*

        impl From<Verified<ExonumMessage>> for Message {
            fn from(msg: Verified<ExonumMessage>) -> Self {
                let raw = msg.raw;
                match msg.inner {
                    $(
                        ExonumMessage::$concrete(inner) => {
                            let inner = Verified::<$concrete> { raw, inner };
                            Self::from(inner)
                        }
                    )*
                }
            }
        }
    };
}

impl_message_from_verified! {
    AnyTx: Service,
    Connect: Service,
    Status: Service,
    Precommit: Consensus,
    Prevote: Consensus,
    Propose: Consensus,
    BlockResponse: Responses,
    TransactionsResponse: Responses,
    BlockRequest: Requests,
    PeersRequest: Requests,
    PrevotesRequest: Requests,
    ProposeRequest: Requests,
    TransactionsRequest: Requests,
    PoolTransactionsRequest: Requests
}

impl Requests {
    /// Returns public key of the message recipient.
    pub fn to(&self) -> PublicKey {
        match *self {
            Requests::ProposeRequest(ref msg) => msg.payload().to,
            Requests::TransactionsRequest(ref msg) => msg.payload().to,
            Requests::PrevotesRequest(ref msg) => msg.payload().to,
            Requests::PeersRequest(ref msg) => msg.payload().to,
            Requests::BlockRequest(ref msg) => msg.payload().to,
            Requests::PoolTransactionsRequest(ref msg) => msg.payload().to,
        }
    }

    /// Returns author public key of the message sender.
    pub fn author(&self) -> PublicKey {
        match *self {
            Requests::ProposeRequest(ref msg) => msg.author(),
            Requests::TransactionsRequest(ref msg) => msg.author(),
            Requests::PrevotesRequest(ref msg) => msg.author(),
            Requests::PeersRequest(ref msg) => msg.author(),
            Requests::BlockRequest(ref msg) => msg.author(),
            Requests::PoolTransactionsRequest(ref msg) => msg.author(),
        }
    }
}

impl Consensus {
    /// Returns author public key of the message sender.
    pub fn author(&self) -> PublicKey {
        match *self {
            Consensus::Propose(ref msg) => msg.author(),
            Consensus::Prevote(ref msg) => msg.author(),
            Consensus::Precommit(ref msg) => msg.author(),
        }
    }

    /// Returns validator id of the message sender.
    pub fn validator(&self) -> ValidatorId {
        match *self {
            Consensus::Propose(ref msg) => msg.payload().validator(),
            Consensus::Prevote(ref msg) => msg.payload().validator(),
            Consensus::Precommit(ref msg) => msg.payload().validator(),
        }
    }

    /// Returns height of the message.
    pub fn height(&self) -> Height {
        match *self {
            Consensus::Propose(ref msg) => msg.payload().height(),
            Consensus::Prevote(ref msg) => msg.payload().height(),
            Consensus::Precommit(ref msg) => msg.payload().height(),
        }
    }

    /// Returns round of the message.
    pub fn round(&self) -> Round {
        match *self {
            Consensus::Propose(ref msg) => msg.payload().round(),
            Consensus::Prevote(ref msg) => msg.payload().round(),
            Consensus::Precommit(ref msg) => msg.payload().round(),
        }
    }
}

impl BinaryValue for Message {
    fn to_bytes(&self) -> Vec<u8> {
        self.as_raw().to_bytes()
    }

    fn from_bytes(value: Cow<'_, [u8]>) -> Result<Self, failure::Error> {
        let message = SignedMessage::from_bytes(value)?;
        Self::from_signed(message)
    }
}

impl ObjectHash for Message {
    fn object_hash(&self) -> Hash {
        self.as_raw().object_hash()
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 The vulkano developers
// 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. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

// For the purpose of this example all unused code is allowed.
#![allow(dead_code)]

extern crate examples;
extern crate cgmath;
extern crate winit;
extern crate time;

#[macro_use]
extern crate vulkano;
#[macro_use]
extern crate vulkano_shader_derive;
extern crate vulkano_win;

use vulkano_win::VkSurfaceBuild;
use vulkano::sync::GpuFuture;

use std::sync::Arc;

fn main() {
    // The start of this example is exactly the same as `triangle`. You should read the
    // `triangle` example if you haven't done so yet.

    let extensions = vulkano_win::required_extensions();
    let instance = vulkano::instance::Instance::new(None, &extensions, None).expect("failed to create instance");

    let physical = vulkano::instance::PhysicalDevice::enumerate(&instance)
                            .next().expect("no device available");
    println!("Using device: {} (type: {:?})", physical.name(), physical.ty());

    let mut events_loop = winit::EventsLoop::new();
    let surface = winit::WindowBuilder::new().build_vk_surface(&events_loop, instance.clone()).unwrap();

    let mut dimensions;

    let queue = physical.queue_families().find(|&q| q.supports_graphics() &&
                                                   surface.is_supported(q).unwrap_or(false))
                                                .expect("couldn't find a graphical queue family");

    let device_ext = vulkano::device::DeviceExtensions {
        khr_swapchain: true,
        .. vulkano::device::DeviceExtensions::none()
    };

    let (device, mut queues) = vulkano::device::Device::new(physical, physical.supported_features(),
                                                            &device_ext, [(queue, 0.5)].iter().cloned())
                               .expect("failed to create device");
    let queue = queues.next().unwrap();

    let (mut swapchain, mut images) = {
        let caps = surface.capabilities(physical).expect("failed to get surface capabilities");

        dimensions = caps.current_extent.unwrap_or([1024, 768]);

        let usage = caps.supported_usage_flags;
        let format = caps.supported_formats[0].0;
        let alpha = caps.supported_composite_alpha.iter().next().unwrap();

        vulkano::swapchain::Swapchain::new(device.clone(), surface.clone(), caps.min_image_count, format, dimensions, 1,
                                           usage, &queue, vulkano::swapchain::SurfaceTransform::Identity,
                                           alpha,
                                           vulkano::swapchain::PresentMode::Fifo, true, None).expect("failed to create swapchain")
    };

    let mut depth_buffer = vulkano::image::attachment::AttachmentImage::transient(device.clone(), dimensions, vulkano::format::D16Unorm).unwrap();

    let vertex_buffer = vulkano::buffer::cpu_access::CpuAccessibleBuffer
                                ::from_iter(device.clone(), vulkano::buffer::BufferUsage::all(), examples::VERTICES.iter().cloned())
                                .expect("failed to create buffer");

    let normals_buffer = vulkano::buffer::cpu_access::CpuAccessibleBuffer
                                ::from_iter(device.clone(), vulkano::buffer::BufferUsage::all(), examples::NORMALS.iter().cloned())
                                .expect("failed to create buffer");

    let index_buffer = vulkano::buffer::cpu_access::CpuAccessibleBuffer
                                ::from_iter(device.clone(), vulkano::buffer::BufferUsage::all(), examples::INDICES.iter().cloned())
                                .expect("failed to create buffer");

    // note: this teapot was meant for OpenGL where the origin is at the lower left
    //       instead the origin is at the upper left in vulkan, so we reverse the Y axis
    let mut proj = cgmath::perspective(cgmath::Rad(std::f32::consts::FRAC_PI_2), { dimensions[0] as f32 / dimensions[1] as f32 }, 0.01, 100.0);
    let view = cgmath::Matrix4::look_at(cgmath::Point3::new(0.3, 0.3, 1.0), cgmath::Point3::new(0.0, 0.0, 0.0), cgmath::Vector3::new(0.0, -1.0, 0.0));
    let scale = cgmath::Matrix4::from_scale(0.01);

    let uniform_buffer = vulkano::buffer::cpu_pool::CpuBufferPool::<vs::ty::Data>
                               ::new(device.clone(), vulkano::buffer::BufferUsage::all());

    let vs = vs::Shader::load(device.clone()).expect("failed to create shader module");
    let fs = fs::Shader::load(device.clone()).expect("failed to create shader module");

    let renderpass = Arc::new(
        single_pass_renderpass!(device.clone(),
            attachments: {
                color: {
                    load: Clear,
                    store: Store,
                    format: swapchain.format(),
                    samples: 1,
                },
                depth: {
                    load: Clear,
                    store: DontCare,
                    format: vulkano::format::Format::D16Unorm,
                    samples: 1,
                }
            },
            pass: {
                color: [color],
                depth_stencil: {depth}
            }
        ).unwrap()
    );

    let pipeline = Arc::new(vulkano::pipeline::GraphicsPipeline::start()
        .vertex_input(vulkano::pipeline::vertex::TwoBuffersDefinition::new())
        .vertex_shader(vs.main_entry_point(), ())
        .triangle_list()
        .viewports_dynamic_scissors_irrelevant(1)
        .fragment_shader(fs.main_entry_point(), ())
        .depth_stencil_simple_depth()
        .render_pass(vulkano::framebuffer::Subpass::from(renderpass.clone(), 0).unwrap())
        .build(device.clone())
                            .unwrap());
    let mut framebuffers: Option<Vec<Arc<vulkano::framebuffer::Framebuffer<_,_>>>> = None;

    let mut recreate_swapchain = false;

    let mut previous_frame = Box::new(vulkano::sync::now(device.clone())) as Box<GpuFuture>;
    let rotation_start = std::time::Instant::now();

    loop {
        previous_frame.cleanup_finished();

        if recreate_swapchain {

        dimensions = surface.capabilities(physical)
            .expect("failed to get surface capabilities")
            .current_extent.unwrap_or([1024, 768]);

            let (new_swapchain, new_images) = match swapchain.recreate_with_dimension(dimensions) {
                Ok(r) => r,
                Err(vulkano::swapchain::SwapchainCreationError::UnsupportedDimensions) => {
                    continue;
                },
                Err(err) => panic!("{:?}", err)
            };

            std::mem::replace(&mut swapchain, new_swapchain);
            std::mem::replace(&mut images, new_images);

            let new_depth_buffer = vulkano::image::attachment::AttachmentImage::transient(device.clone(), dimensions, vulkano::format::D16Unorm).unwrap();
            std::mem::replace(&mut depth_buffer, new_depth_buffer);

            framebuffers = None;

            proj = cgmath::perspective(cgmath::Rad(std::f32::consts::FRAC_PI_2), { dimensions[0] as f32 / dimensions[1] as f32 }, 0.01, 100.0);

            recreate_swapchain = false;
        }

        if framebuffers.is_none() {
            let new_framebuffers = Some(images.iter().map(|image| {
                Arc::new(vulkano::framebuffer::Framebuffer::start(renderpass.clone())
                         .add(image.clone()).unwrap()
                         .add(depth_buffer.clone()).unwrap()
                         .build().unwrap())
            }).collect::<Vec<_>>());
            std::mem::replace(&mut framebuffers, new_framebuffers);
        }

        let uniform_buffer_subbuffer = {
            let elapsed = rotation_start.elapsed();
            let rotation = elapsed.as_secs() as f64 + elapsed.subsec_nanos() as f64 / 1_000_000_000.0;
            let rotation = cgmath::Matrix3::from_angle_y(cgmath::Rad(rotation as f32));

            let uniform_data = vs::ty::Data {
                world : cgmath::Matrix4::from(rotation).into(),
                view : (view * scale).into(),
                proj : proj.into(),
            };

            uniform_buffer.next(uniform_data).unwrap()
        };

        let set = Arc::new(vulkano::descriptor::descriptor_set::PersistentDescriptorSet::start(pipeline.clone(), 0)
            .add_buffer(uniform_buffer_subbuffer).unwrap()
            .build().unwrap()
        );

        let (image_num, acquire_future) = match vulkano::swapchain::acquire_next_image(swapchain.clone(),
                                                                                None) {
            Ok(r) => r,
            Err(vulkano::swapchain::AcquireError::OutOfDate) => {
                recreate_swapchain = true;
                continue;
            },
            Err(err) => panic!("{:?}", err)
        };

        let command_buffer = vulkano::command_buffer::AutoCommandBufferBuilder::primary_one_time_submit(device.clone(), queue.family()).unwrap()
            .begin_render_pass(
                framebuffers.as_ref().unwrap()[image_num].clone(), false,
                vec![
                    [0.0, 0.0, 1.0, 1.0].into(),
                    1f32.into()
                ]).unwrap()
            .draw_indexed(
                pipeline.clone(),
                vulkano::command_buffer::DynamicState {
                      line_width: None,
                      viewports: Some(vec![vulkano::pipeline::viewport::Viewport {
                          origin: [0.0, 0.0],
                          dimensions: [dimensions[0] as f32, dimensions[1] as f32],
                          depth_range: 0.0 .. 1.0,
                      }]),
                      scissors: None,
                },
                (vertex_buffer.clone(), normals_buffer.clone()),
                index_buffer.clone(), set.clone(), ()).unwrap()
            .end_render_pass().unwrap()
            .build().unwrap();

        let future = previous_frame.join(acquire_future)
            .then_execute(queue.clone(), command_buffer).unwrap()
            .then_swapchain_present(queue.clone(), swapchain.clone(), image_num)
            .then_signal_fence_and_flush();

        match future {
            Ok(future) => {
                previous_frame = Box::new(future) as Box<_>;
            }
            Err(vulkano::sync::FlushError::OutOfDate) => {
                recreate_swapchain = true;
                previous_frame = Box::new(vulkano::sync::now(device.clone())) as Box<_>;
            }
            Err(e) => {
                println!("{:?}", e);
                previous_frame = Box::new(vulkano::sync::now(device.clone())) as Box<_>;
            }
        }

        let mut done = false;
        events_loop.poll_events(|ev| {
            match ev {
                winit::Event::WindowEvent { event: winit::WindowEvent::CloseRequested, .. } => done = true,
                _ => ()
            }
        });
        if done { return; }
    }
}

mod vs {
    #[derive(VulkanoShader)]
    #[ty = "vertex"]
    #[src = "
#version 450

layout(location = 0) in vec3 position;
layout(location = 1) in vec3 normal;

layout(location = 0) out vec3 v_normal;

layout(set = 0, binding = 0) uniform Data {
    mat4 world;
    mat4 view;
    mat4 proj;
} uniforms;

void main() {
    mat4 worldview = uniforms.view * uniforms.world;
    v_normal = transpose(inverse(mat3(worldview))) * normal;
    gl_Position = uniforms.proj * worldview * vec4(position, 1.0);
}
"]
    struct Dummy;
}

mod fs {
    #[derive(VulkanoShader)]
    #[ty = "fragment"]
    #[src = "
#version 450

layout(location = 0) in vec3 v_normal;
layout(location = 0) out vec4 f_color;

const vec3 LIGHT = vec3(0.0, 0.0, 1.0);

void main() {
    float brightness = dot(normalize(v_normal), normalize(LIGHT));
    vec3 dark_color = vec3(0.6, 0.0, 0.0);
    vec3 regular_color = vec3(1.0, 0.0, 0.0);

    f_color = vec4(mix(dark_color, regular_color, brightness), 1.0);
}
"]
    struct Dummy;
}
<commit_msg>Avoid gratuitous use of std::mem::replace. (#1005)<commit_after>// Copyright (c) 2016 The vulkano developers
// 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. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

// For the purpose of this example all unused code is allowed.
#![allow(dead_code)]

extern crate examples;
extern crate cgmath;
extern crate winit;
extern crate time;

#[macro_use]
extern crate vulkano;
#[macro_use]
extern crate vulkano_shader_derive;
extern crate vulkano_win;

use vulkano_win::VkSurfaceBuild;
use vulkano::sync::GpuFuture;

use std::sync::Arc;

fn main() {
    // The start of this example is exactly the same as `triangle`. You should read the
    // `triangle` example if you haven't done so yet.

    let extensions = vulkano_win::required_extensions();
    let instance = vulkano::instance::Instance::new(None, &extensions, None).expect("failed to create instance");

    let physical = vulkano::instance::PhysicalDevice::enumerate(&instance)
                            .next().expect("no device available");
    println!("Using device: {} (type: {:?})", physical.name(), physical.ty());

    let mut events_loop = winit::EventsLoop::new();
    let surface = winit::WindowBuilder::new().build_vk_surface(&events_loop, instance.clone()).unwrap();

    let mut dimensions;

    let queue = physical.queue_families().find(|&q| q.supports_graphics() &&
                                                   surface.is_supported(q).unwrap_or(false))
                                                .expect("couldn't find a graphical queue family");

    let device_ext = vulkano::device::DeviceExtensions {
        khr_swapchain: true,
        .. vulkano::device::DeviceExtensions::none()
    };

    let (device, mut queues) = vulkano::device::Device::new(physical, physical.supported_features(),
                                                            &device_ext, [(queue, 0.5)].iter().cloned())
                               .expect("failed to create device");
    let queue = queues.next().unwrap();

    let (mut swapchain, mut images) = {
        let caps = surface.capabilities(physical).expect("failed to get surface capabilities");

        dimensions = caps.current_extent.unwrap_or([1024, 768]);

        let usage = caps.supported_usage_flags;
        let format = caps.supported_formats[0].0;
        let alpha = caps.supported_composite_alpha.iter().next().unwrap();

        vulkano::swapchain::Swapchain::new(device.clone(), surface.clone(), caps.min_image_count, format, dimensions, 1,
                                           usage, &queue, vulkano::swapchain::SurfaceTransform::Identity,
                                           alpha,
                                           vulkano::swapchain::PresentMode::Fifo, true, None).expect("failed to create swapchain")
    };

    let mut depth_buffer = vulkano::image::attachment::AttachmentImage::transient(device.clone(), dimensions, vulkano::format::D16Unorm).unwrap();

    let vertex_buffer = vulkano::buffer::cpu_access::CpuAccessibleBuffer
                                ::from_iter(device.clone(), vulkano::buffer::BufferUsage::all(), examples::VERTICES.iter().cloned())
                                .expect("failed to create buffer");

    let normals_buffer = vulkano::buffer::cpu_access::CpuAccessibleBuffer
                                ::from_iter(device.clone(), vulkano::buffer::BufferUsage::all(), examples::NORMALS.iter().cloned())
                                .expect("failed to create buffer");

    let index_buffer = vulkano::buffer::cpu_access::CpuAccessibleBuffer
                                ::from_iter(device.clone(), vulkano::buffer::BufferUsage::all(), examples::INDICES.iter().cloned())
                                .expect("failed to create buffer");

    // note: this teapot was meant for OpenGL where the origin is at the lower left
    //       instead the origin is at the upper left in vulkan, so we reverse the Y axis
    let mut proj = cgmath::perspective(cgmath::Rad(std::f32::consts::FRAC_PI_2), { dimensions[0] as f32 / dimensions[1] as f32 }, 0.01, 100.0);
    let view = cgmath::Matrix4::look_at(cgmath::Point3::new(0.3, 0.3, 1.0), cgmath::Point3::new(0.0, 0.0, 0.0), cgmath::Vector3::new(0.0, -1.0, 0.0));
    let scale = cgmath::Matrix4::from_scale(0.01);

    let uniform_buffer = vulkano::buffer::cpu_pool::CpuBufferPool::<vs::ty::Data>
                               ::new(device.clone(), vulkano::buffer::BufferUsage::all());

    let vs = vs::Shader::load(device.clone()).expect("failed to create shader module");
    let fs = fs::Shader::load(device.clone()).expect("failed to create shader module");

    let renderpass = Arc::new(
        single_pass_renderpass!(device.clone(),
            attachments: {
                color: {
                    load: Clear,
                    store: Store,
                    format: swapchain.format(),
                    samples: 1,
                },
                depth: {
                    load: Clear,
                    store: DontCare,
                    format: vulkano::format::Format::D16Unorm,
                    samples: 1,
                }
            },
            pass: {
                color: [color],
                depth_stencil: {depth}
            }
        ).unwrap()
    );

    let pipeline = Arc::new(vulkano::pipeline::GraphicsPipeline::start()
        .vertex_input(vulkano::pipeline::vertex::TwoBuffersDefinition::new())
        .vertex_shader(vs.main_entry_point(), ())
        .triangle_list()
        .viewports_dynamic_scissors_irrelevant(1)
        .fragment_shader(fs.main_entry_point(), ())
        .depth_stencil_simple_depth()
        .render_pass(vulkano::framebuffer::Subpass::from(renderpass.clone(), 0).unwrap())
        .build(device.clone())
                            .unwrap());
    let mut framebuffers: Option<Vec<Arc<vulkano::framebuffer::Framebuffer<_,_>>>> = None;

    let mut recreate_swapchain = false;

    let mut previous_frame = Box::new(vulkano::sync::now(device.clone())) as Box<GpuFuture>;
    let rotation_start = std::time::Instant::now();

    loop {
        previous_frame.cleanup_finished();

        if recreate_swapchain {

        dimensions = surface.capabilities(physical)
            .expect("failed to get surface capabilities")
            .current_extent.unwrap_or([1024, 768]);

            let (new_swapchain, new_images) = match swapchain.recreate_with_dimension(dimensions) {
                Ok(r) => r,
                Err(vulkano::swapchain::SwapchainCreationError::UnsupportedDimensions) => {
                    continue;
                },
                Err(err) => panic!("{:?}", err)
            };

            swapchain = new_swapchain;
            images = new_images;

            let new_depth_buffer = vulkano::image::attachment::AttachmentImage::transient(device.clone(), dimensions, vulkano::format::D16Unorm).unwrap();
            std::mem::replace(&mut depth_buffer, new_depth_buffer);

            framebuffers = None;

            proj = cgmath::perspective(cgmath::Rad(std::f32::consts::FRAC_PI_2), { dimensions[0] as f32 / dimensions[1] as f32 }, 0.01, 100.0);

            recreate_swapchain = false;
        }

        if framebuffers.is_none() {
            let new_framebuffers = Some(images.iter().map(|image| {
                Arc::new(vulkano::framebuffer::Framebuffer::start(renderpass.clone())
                         .add(image.clone()).unwrap()
                         .add(depth_buffer.clone()).unwrap()
                         .build().unwrap())
            }).collect::<Vec<_>>());
            std::mem::replace(&mut framebuffers, new_framebuffers);
        }

        let uniform_buffer_subbuffer = {
            let elapsed = rotation_start.elapsed();
            let rotation = elapsed.as_secs() as f64 + elapsed.subsec_nanos() as f64 / 1_000_000_000.0;
            let rotation = cgmath::Matrix3::from_angle_y(cgmath::Rad(rotation as f32));

            let uniform_data = vs::ty::Data {
                world : cgmath::Matrix4::from(rotation).into(),
                view : (view * scale).into(),
                proj : proj.into(),
            };

            uniform_buffer.next(uniform_data).unwrap()
        };

        let set = Arc::new(vulkano::descriptor::descriptor_set::PersistentDescriptorSet::start(pipeline.clone(), 0)
            .add_buffer(uniform_buffer_subbuffer).unwrap()
            .build().unwrap()
        );

        let (image_num, acquire_future) = match vulkano::swapchain::acquire_next_image(swapchain.clone(),
                                                                                None) {
            Ok(r) => r,
            Err(vulkano::swapchain::AcquireError::OutOfDate) => {
                recreate_swapchain = true;
                continue;
            },
            Err(err) => panic!("{:?}", err)
        };

        let command_buffer = vulkano::command_buffer::AutoCommandBufferBuilder::primary_one_time_submit(device.clone(), queue.family()).unwrap()
            .begin_render_pass(
                framebuffers.as_ref().unwrap()[image_num].clone(), false,
                vec![
                    [0.0, 0.0, 1.0, 1.0].into(),
                    1f32.into()
                ]).unwrap()
            .draw_indexed(
                pipeline.clone(),
                vulkano::command_buffer::DynamicState {
                      line_width: None,
                      viewports: Some(vec![vulkano::pipeline::viewport::Viewport {
                          origin: [0.0, 0.0],
                          dimensions: [dimensions[0] as f32, dimensions[1] as f32],
                          depth_range: 0.0 .. 1.0,
                      }]),
                      scissors: None,
                },
                (vertex_buffer.clone(), normals_buffer.clone()),
                index_buffer.clone(), set.clone(), ()).unwrap()
            .end_render_pass().unwrap()
            .build().unwrap();

        let future = previous_frame.join(acquire_future)
            .then_execute(queue.clone(), command_buffer).unwrap()
            .then_swapchain_present(queue.clone(), swapchain.clone(), image_num)
            .then_signal_fence_and_flush();

        match future {
            Ok(future) => {
                previous_frame = Box::new(future) as Box<_>;
            }
            Err(vulkano::sync::FlushError::OutOfDate) => {
                recreate_swapchain = true;
                previous_frame = Box::new(vulkano::sync::now(device.clone())) as Box<_>;
            }
            Err(e) => {
                println!("{:?}", e);
                previous_frame = Box::new(vulkano::sync::now(device.clone())) as Box<_>;
            }
        }

        let mut done = false;
        events_loop.poll_events(|ev| {
            match ev {
                winit::Event::WindowEvent { event: winit::WindowEvent::CloseRequested, .. } => done = true,
                _ => ()
            }
        });
        if done { return; }
    }
}

mod vs {
    #[derive(VulkanoShader)]
    #[ty = "vertex"]
    #[src = "
#version 450

layout(location = 0) in vec3 position;
layout(location = 1) in vec3 normal;

layout(location = 0) out vec3 v_normal;

layout(set = 0, binding = 0) uniform Data {
    mat4 world;
    mat4 view;
    mat4 proj;
} uniforms;

void main() {
    mat4 worldview = uniforms.view * uniforms.world;
    v_normal = transpose(inverse(mat3(worldview))) * normal;
    gl_Position = uniforms.proj * worldview * vec4(position, 1.0);
}
"]
    struct Dummy;
}

mod fs {
    #[derive(VulkanoShader)]
    #[ty = "fragment"]
    #[src = "
#version 450

layout(location = 0) in vec3 v_normal;
layout(location = 0) out vec4 f_color;

const vec3 LIGHT = vec3(0.0, 0.0, 1.0);

void main() {
    float brightness = dot(normalize(v_normal), normalize(LIGHT));
    vec3 dark_color = vec3(0.6, 0.0, 0.0);
    vec3 regular_color = vec3(1.0, 0.0, 0.0);

    f_color = vec4(mix(dark_color, regular_color, brightness), 1.0);
}
"]
    struct Dummy;
}
<|endoftext|>