ciruela 0.6.12

A peer-to-peer synchronization software for servers in datacenters.
Documentation
use std::fmt;

use serde::{Deserialize, Deserializer};
use serde::de::{Visitor, SeqAccess, Error};

use proto::{dir_commands, index_commands, block_commands, p2p_commands};
use proto::{NOTIFICATION, REQUEST, RESPONSE};




pub enum Message {
    Request(u64, Request),
    Response(u64, Response),
    Notification(Notification),
}

struct MessageVisitor;
struct RequestTypeVisitor;
struct ResponseTypeVisitor;
struct NotificationTypeVisitor;

pub enum RequestType {
    AppendDir,
    ReplaceDir,
    GetIndex,
    GetIndexAt,
    GetBlock,
    GetBaseDir,
}

pub enum ResponseType {
    AppendDir,
    ReplaceDir,
    GetIndex,
    GetIndexAt,
    GetBlock,
    GetBaseDir,
    RequestError,
}

pub enum NotificationType {
    PublishImage,
    ReceivedImage,
    AbortedImage,
}

const REQUEST_TYPES: &'static [&'static str] = &[
    "AppendDir",
    "ReplaceDir",
    "GetIndex",
    "GetIndexAt",
    "GetBlock",
    "GetBaseDir",
    ];

const RESPONSE_TYPES: &'static [&'static str] = &[
    "AppendDir",
    "ReplaceDir",
    "GetIndex",
    "GetIndexAt",
    "GetBlock",
    "GetBaseDir",
    ];

const NOTIFICATION_TYPES: &'static [&'static str] = &[
    "PublishImage",
    "ReceivedImage",
    "AbortedImage",
    ];

pub enum Request {
    AppendDir(dir_commands::AppendDir),
    ReplaceDir(dir_commands::ReplaceDir),
    GetIndex(index_commands::GetIndex),
    GetIndexAt(index_commands::GetIndexAt),
    GetBlock(block_commands::GetBlock),
    GetBaseDir(p2p_commands::GetBaseDir),
}

pub enum Response {
    AppendDir(dir_commands::AppendDirAck),
    ReplaceDir(dir_commands::ReplaceDirAck),
    GetIndex(index_commands::GetIndexResponse),
    GetIndexAt(index_commands::GetIndexAtResponse),
    GetBlock(block_commands::GetBlockResponse),
    GetBaseDir(p2p_commands::GetBaseDirResponse),
    Error(String),
}

#[derive(Debug)]
pub enum Notification {
    PublishImage(index_commands::PublishImage),
    ReceivedImage(index_commands::ReceivedImage),
    AbortedImage(index_commands::AbortedImage),
}

impl<'a> Deserialize<'a> for Message {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
        where D: Deserializer<'a>
    {
        deserializer.deserialize_seq(MessageVisitor)
    }
}

impl<'a> Visitor<'a> for RequestTypeVisitor {
    type Value = RequestType;
    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str(&REQUEST_TYPES.join(", "))
    }

    fn visit_str<E>(self, value: &str) -> Result<RequestType, E>
        where E: Error
    {
        match value {
            "AppendDir" => Ok(RequestType::AppendDir),
            "ReplaceDir" => Ok(RequestType::ReplaceDir),
            "GetIndex" => Ok(RequestType::GetIndex),
            "GetIndexAt" => Ok(RequestType::GetIndexAt),
            "GetBlock" => Ok(RequestType::GetBlock),
            "GetBaseDir" => Ok(RequestType::GetBaseDir),
            _ => Err(Error::unknown_variant(value, REQUEST_TYPES)),
        }
    }
}

impl<'a> Visitor<'a> for ResponseTypeVisitor {
    type Value = ResponseType;
    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str(&RESPONSE_TYPES.join(", "))
    }

    fn visit_str<E>(self, value: &str) -> Result<ResponseType, E>
        where E: Error
    {
        match value {
            "AppendDir" => Ok(ResponseType::AppendDir),
            "ReplaceDir" => Ok(ResponseType::ReplaceDir),
            "GetIndex" => Ok(ResponseType::GetIndex),
            "GetIndexAt" => Ok(ResponseType::GetIndexAt),
            "GetBlock" => Ok(ResponseType::GetBlock),
            "GetBaseDir" => Ok(ResponseType::GetBaseDir),
            "Error" => Ok(ResponseType::RequestError),
            _ => Err(Error::unknown_variant(value, RESPONSE_TYPES)),
        }
    }
}

impl<'a> Visitor<'a> for NotificationTypeVisitor {
    type Value = NotificationType;
    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str(&NOTIFICATION_TYPES.join(", "))
    }

    fn visit_str<E>(self, value: &str) -> Result<NotificationType, E>
        where E: Error
    {
        match value {
            "PublishImage" => Ok(NotificationType::PublishImage),
            "ReceivedImage" => Ok(NotificationType::ReceivedImage),
            "AbortedImage" => Ok(NotificationType::AbortedImage),
            _ => Err(Error::unknown_field(value, NOTIFICATION_TYPES)),
        }
    }
}

impl<'a> Deserialize<'a> for RequestType {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
        where D: Deserializer<'a>
    {
        deserializer.deserialize_str(RequestTypeVisitor)
    }
}

impl<'a> Deserialize<'a> for ResponseType {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
        where D: Deserializer<'a>
    {
        deserializer.deserialize_str(ResponseTypeVisitor)
    }
}

impl<'a> Deserialize<'a> for NotificationType {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
        where D: Deserializer<'a>
    {
        deserializer.deserialize_str(NotificationTypeVisitor)
    }
}

impl<'a> Visitor<'a> for MessageVisitor {
    type Value = Message;

    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str("a request, response or a notification")
    }

    #[inline]
    fn visit_seq<V>(self, mut visitor: V) -> Result<Message, V::Error>
        where V: SeqAccess<'a>,
    {
        match visitor.next_element()? {
            Some(NOTIFICATION) => {
                let typ = match visitor.next_element()? {
                    Some(typ) => typ,
                    None => return Err(Error::invalid_length(1, &self)),
                };
                let data = match typ {
                    NotificationType::PublishImage => match visitor.next_element()? {
                        Some(data) => Notification::PublishImage(data),
                        None => return Err(Error::invalid_length(3, &self)),
                    },
                    NotificationType::ReceivedImage => match visitor.next_element()? {
                        Some(data) => Notification::ReceivedImage(data),
                        None => return Err(Error::invalid_length(3, &self)),
                    },
                    NotificationType::AbortedImage => match visitor.next_element()? {
                        Some(data) => Notification::AbortedImage(data),
                        None => return Err(Error::invalid_length(3, &self)),
                    },
                };
                Ok(Message::Notification(data))
            }
            Some(REQUEST) => {
                use self::RequestType::*;
                let typ = match visitor.next_element()? {
                    Some(typ) => typ,
                    None => return Err(Error::invalid_length(1, &self)),
                };
                let request_id = match visitor.next_element()? {
                    Some(x) => x,
                    None => return Err(Error::invalid_length(2, &self)),
                };
                let data = match typ {
                    AppendDir => match visitor.next_element()? {
                        Some(data) => Request::AppendDir(data),
                        None => return Err(Error::invalid_length(3, &self)),
                    },
                    ReplaceDir => match visitor.next_element()? {
                        Some(data) => Request::ReplaceDir(data),
                        None => return Err(Error::invalid_length(3, &self)),
                    },
                    GetIndex => match visitor.next_element()? {
                        Some(data) => Request::GetIndex(data),
                        None => return Err(Error::invalid_length(3, &self)),
                    },
                    GetIndexAt => match visitor.next_element()? {
                        Some(data) => Request::GetIndexAt(data),
                        None => return Err(Error::invalid_length(2, &self)),
                    },
                    GetBlock => match visitor.next_element()? {
                        Some(data) => Request::GetBlock(data),
                        None => return Err(Error::invalid_length(3, &self)),
                    },
                    GetBaseDir => match visitor.next_element()? {
                        Some(data) => Request::GetBaseDir(data),
                        None => return Err(Error::invalid_length(3, &self)),
                    },
                };
                Ok(Message::Request(request_id, data))
            },
            Some(RESPONSE) => {
                use self::ResponseType::*;
                let typ = match visitor.next_element()? {
                    Some(typ) => typ,
                    None => return Err(Error::invalid_length(1, &self)),
                };
                let request_id = match visitor.next_element()? {
                    Some(x) => x,
                    None => return Err(Error::invalid_length(2, &self)),
                };
                let data = match typ {
                    AppendDir => match visitor.next_element()? {
                        Some(data) => Response::AppendDir(data),
                        None => return Err(Error::invalid_length(3, &self)),
                    },
                    ReplaceDir => match visitor.next_element()? {
                        Some(data) => Response::ReplaceDir(data),
                        None => return Err(Error::invalid_length(3, &self)),
                    },
                    GetIndex => match visitor.next_element()? {
                        Some(data) => Response::GetIndex(data),
                        None => return Err(Error::invalid_length(3, &self)),
                    },
                    GetIndexAt => match visitor.next_element()? {
                        Some(data) => Response::GetIndexAt(data),
                        None => return Err(Error::invalid_length(3, &self)),
                    },
                    GetBlock => match visitor.next_element()? {
                        Some(data) => Response::GetBlock(data),
                        None => return Err(Error::invalid_length(3, &self)),
                    },
                    GetBaseDir => match visitor.next_element()? {
                        Some(data) => Response::GetBaseDir(data),
                        None => return Err(Error::invalid_length(3, &self)),
                    },
                    RequestError => match visitor.next_element()? {
                        Some(data) => Response::Error(data),
                        None => return Err(Error::invalid_length(3, &self)),
                    },
                };
                Ok(Message::Response(request_id, data))
            }
            Some(_) => Err(Error::custom("invalid message kind")),
            None => Err(Error::invalid_length(0, &self)),
        }
    }
}