1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
use {Error, Parcel, Settings};
use hint;
use std::io::prelude::*;
use std::fmt;

/// A high level abstraction over a lower-level `Parcel`.
///
/// Automatically marshals values to and from the high level
/// and low level types for serialization.
///
/// # Example
///
/// ```
/// #[macro_use] extern crate protocol_derive;
/// extern crate protocol;
///
/// use protocol::Parcel;
///
/// #[derive(Protocol)]
/// pub struct RawPacket {
///     opcode: u8,
///     magic_number: u8,
///     payload: Vec<u8>,
///     version: (u8, u8),
/// }
///
/// #[derive(Debug, Clone)]
/// pub enum Login {
///     Success {
///         message: String,
///     },
///     Failure {
///         code: FailureCode,
///         response: String,
///     },
/// }
///
/// impl protocol::HighLevel for Login {
///     type LowLevel = RawPacket;
///
///     fn into_low_level(self) -> RawPacket {
///         match self {
///             Login::Success { message } => {
///                 RawPacket {
///                     opcode: 0,
///                     magic_number: 0xaa,
///                     payload: message.into_bytes(),
///                     version: (11, 0),
///                 }
///             },
///             Login::Failure { .. } => unimplemented!(),
///         }
///     }
///
///     fn from_low_level(low_level: RawPacket,
///                       _: &mut std::io::Read,
///                       _: &protocol::Settings,
///                       _: &mut protocol::hint::Hints)
///         -> Result<Self, protocol::Error> {
///         match low_level.opcode {
///             0 => Ok(Login::Success { message: String::from_utf8(low_level.payload).unwrap() }),
///             1 => Ok(Login::Failure {
///                 code: FailureCode::MyDogAteMyHomework,
///                 response: String::from_utf8(low_level.payload[1..].to_owned()).unwrap() }),
///             _ => unreachable!(),
///         }
///     }
/// }
///
/// #[derive(Debug, Clone)]
/// pub enum FailureCode {
///     MyDogAteMyHomework,
/// }
///
/// let high_level = Login::Success { message: "Hi!".to_owned() };
/// assert_eq!(11, high_level.raw_bytes(&protocol::Settings::default()).unwrap().len());
/// ```
pub trait HighLevel : Clone + fmt::Debug {
    /// The lower-level representation of this type.
    type LowLevel: Parcel;

    /// Converts this high level type into its lower-level representation.
    fn into_low_level(self) -> Self::LowLevel;

    /// Creates a high-level abstraction over a lower-level value.
    ///
    /// The method has access to the reader post-parsing of the low level type.
    /// It is not necessary to use this if not needed.
    fn from_low_level(value: Self::LowLevel,
                      subsequent_reader: &mut Read,
                      settings: &Settings,
                      hints: &mut hint::Hints) -> Result<Self, Error>;
}

impl<H> Parcel for H
    where H: HighLevel {
    const TYPE_NAME: &'static str = "HighLevel";

    fn read_field(read: &mut Read,
                  settings: &Settings,
                  hints: &mut hint::Hints) -> Result<Self, Error> {
        let low_level = H::LowLevel::read_field(read, settings, hints)?;
        H::from_low_level(low_level, read, settings, hints)
    }

    fn write_field(&self,
                   write: &mut Write,
                   settings: &Settings,
                   hints: &mut hint::Hints) -> Result<(), Error> {
        let low_level = self.clone().into_low_level();
        low_level.write_field(write, settings, hints)
    }
}