djin_protocol/
high_level.rs

1use crate::{hint, Error, Parcel, Settings};
2use std::io::prelude::*;
3use std::fmt;
4
5/// A high level abstraction over a lower-level `Parcel`.
6///
7/// Automatically marshals values to and from the high level
8/// and low level types for serialization.
9///
10/// # Example
11///
12/// ```
13/// #[macro_use] extern crate djin_protocol_derive;/// extern crate djin_protocol;
14///
15/// use djin_protocol::Parcel;
16///
17/// #[derive(Protocol)]
18/// pub struct RawPacket {
19///     opcode: u8,
20///     magic_number: u8,
21///     payload: Vec<u8>,
22///     version: (u8, u8),
23/// }
24///
25/// #[derive(Debug, Clone)]
26/// pub enum Login {
27///     Success {
28///         message: String,
29///     },
30///     Failure {
31///         code: FailureCode,
32///         response: String,
33///     },
34/// }
35///
36/// impl djin_protocol::HighLevel for Login {
37///     type LowLevel = RawPacket;
38///
39///     fn into_low_level(self) -> RawPacket {
40///         match self {
41///             Login::Success { message } => {
42///                 RawPacket {
43///                     opcode: 0,
44///                     magic_number: 0xaa,
45///                     payload: message.into_bytes(),
46///                     version: (11, 0),
47///                 }
48///             },
49///             Login::Failure { .. } => unimplemented!(),
50///         }
51///     }
52///
53///     fn from_low_level(low_level: RawPacket,
54///                       _: &mut std::io::Read,
55///                       _: &djin_protocol::Settings,
56///                       _: &mut djin_protocol::hint::Hints)
57///         -> Result<Self, djin_protocol::Error> {
58///         match low_level.opcode {
59///             0 => Ok(Login::Success { message: String::from_utf8(low_level.payload).unwrap() }),
60///             1 => Ok(Login::Failure {
61///                 code: FailureCode::MyDogAteMyHomework,
62///                 response: String::from_utf8(low_level.payload[1..].to_owned()).unwrap() }),
63///             _ => unreachable!(),
64///         }
65///     }
66/// }
67///
68/// #[derive(Debug, Clone)]
69/// pub enum FailureCode {
70///     MyDogAteMyHomework,
71/// }
72///
73/// let high_level = Login::Success { message: "Hi!".to_owned() };
74/// assert_eq!(11, high_level.raw_bytes(&djin_protocol::Settings::default()).unwrap().len());
75/// ```
76pub trait HighLevel : Clone + fmt::Debug {
77    /// The lower-level representation of this type.
78    type LowLevel: Parcel;
79
80    /// Converts this high level type into its lower-level representation.
81    fn into_low_level(self) -> Self::LowLevel;
82
83    /// Creates a high-level abstraction over a lower-level value.
84    ///
85    /// The method has access to the reader post-parsing of the low level type.
86    /// It is not necessary to use this if not needed.
87    fn from_low_level(value: Self::LowLevel,
88                      subsequent_reader: &mut dyn Read,
89                      settings: &Settings,
90                      hints: &mut hint::Hints) -> Result<Self, Error>;
91}
92
93impl<H> Parcel for H
94    where H: HighLevel {
95    const TYPE_NAME: &'static str = "HighLevel";
96
97    fn read_field(read: &mut dyn Read,
98                  settings: &Settings,
99                  hints: &mut hint::Hints) -> Result<Self, Error> {
100        let low_level = H::LowLevel::read_field(read, settings, hints)?;
101        H::from_low_level(low_level, read, settings, hints)
102    }
103
104    fn write_field(&self,
105                   write: &mut dyn Write,
106                   settings: &Settings,
107                   hints: &mut hint::Hints) -> Result<(), Error> {
108        let low_level = self.clone().into_low_level();
109        low_level.write_field(write, settings, hints)
110    }
111}
112