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