1extern crate try_from;
59
60pub use try_from::TryInto;
61pub use try_from::TryFrom;
62
63pub trait SubtypeCheck<F, T, E> {
65 fn check_is_valid_subtype(&self) -> Result<(), E>;
66}
67
68#[macro_export]
86macro_rules! subtype_of {
87 ($base:ty => $sub:ty | $cerr:ty $check_fn:block) => (
88 impl $crate::SubtypeCheck<$base, $sub, $cerr> for $base {
89 fn check_is_valid_subtype(&self) -> Result<(), $cerr> $check_fn
90 }
91
92 impl ::std::ops::Deref for $sub {
93 type Target = $base;
94
95 #[inline(always)]
96 fn deref(&self) -> &$base {
97 unsafe { ::std::mem::transmute::<&$sub, &$base>(self) }
98 }
99 }
100
101 impl $crate::TryFrom<$base> for $sub {
102 type Err = $cerr;
103
104 #[inline(always)]
105 fn try_from(base: $base) -> Result<Self, Self::Err> {
106 try!($crate::SubtypeCheck::<$base, $sub, $cerr>::check_is_valid_subtype(&base));
107 Ok(unsafe { ::std::mem::transmute::<$base, $sub>(base) })
108 }
109 }
110
111 impl<'a> $crate::TryFrom<&'a $base> for &'a $sub {
112 type Err = $cerr;
113
114 #[inline(always)]
115 fn try_from(base_ref: &$base) -> Result<Self, Self::Err> {
116 try!($crate::SubtypeCheck::<$base, $sub, $cerr>::check_is_valid_subtype(base_ref));
117 Ok(unsafe { ::std::mem::transmute::<&$base, &$sub>(base_ref) })
118 }
119 }
120
121 impl<'a> $crate::TryFrom<&'a mut $base> for &'a mut $sub {
122 type Err = $cerr;
123
124 #[inline(always)]
125 fn try_from(base_ref: &mut $base) -> Result<Self, Self::Err> {
126 try!($crate::SubtypeCheck::<$base, $sub, $cerr>::check_is_valid_subtype(base_ref));
127 Ok(unsafe { ::std::mem::transmute::<&mut $base, &mut $sub>(base_ref) })
128 }
129 }
130
131 )
132}
133
134#[cfg(test)]
135mod test {
136 use super::TryInto;
137
138 #[repr(C)]
139 pub struct Packet {
140 packet_type: u8,
142
143 data: [u8; 7],
146 }
147
148 #[repr(C)]
149 pub struct StatusPacket {
150 packet_type: u8,
151 ts: [u8; 4],
152 status_0: u8,
153 status_1: u8,
154 status_2: u8,
155 }
156
157 #[repr(C, packed)]
158 pub struct PingPacket {
159 packet_type: u8,
160 dummy: u32,
161 unused: [u8; 3],
162 }
163
164 #[repr(C, packed)]
165 pub struct PongPacket {
166 packet_type: u8,
167 dummy: u32,
168 unused: [u8; 3],
169 }
170
171 pub struct PongConvError {
172
173 }
174
175 subtype_of!(Packet => PingPacket | ConversionError {
176 Ok(())
177 });
178 subtype_of!(Packet => PongPacket | PongConvError {
179 Err(PongConvError {})
180 });
181 subtype_of!(Packet => StatusPacket | () {
182 Ok(())
183 });
184
185 #[derive(Debug)]
186 pub enum ConversionError {}
187
188 impl Packet {
189 pub fn get_raw_payload(&self) -> &[u8] {
190 &self.data
191 }
192
193 pub fn set_raw_payload(&mut self, data: [u8; 7]) {
194 self.data = data
195 }
196
197 pub fn new(packet_type: u8, data: [u8; 7]) -> Packet {
198 Packet {
199 packet_type: packet_type,
200 data: data,
201 }
202 }
203 }
204
205 impl StatusPacket {
206 pub fn get_status_2(&self) -> u8 {
207 self.status_2
208 }
209
210 pub fn set_status_2(&mut self, v: u8) {
211 self.status_2 = v
212 }
213 }
214
215 fn send(packet: &Packet) {
217 let _ = packet.get_raw_payload();
218 }
220
221 fn swallow_status_packet(_: StatusPacket) {
222 }
224
225 #[test]
226 fn test_send() {
227 let mut owned = Packet::new(2, b"0123456".to_owned());
228 send(&owned);
229
230 {
231 let status_view: &StatusPacket = (&owned).try_into().unwrap();
232 send(status_view);
233 }
234
235 let mut status_mut_ref: &mut StatusPacket = (&mut owned).try_into().unwrap();
236 status_mut_ref.set_status_2(0x12);
237 assert_eq!(status_mut_ref.get_status_2(), 0x12);
238 send(&status_mut_ref);
239 }
240
241 #[test]
242 fn send_from_ref() {
243 let mut owned = Packet::new(2, b"0123456".to_owned());
244
245 let pref: &mut Packet = &mut owned;
246
247 send(pref);
248
249 {
250 let status_view: &StatusPacket = (&(*pref)).try_into().unwrap();
255 send(&status_view);
256 }
257
258 let mut status_mut_view: &mut StatusPacket = pref.try_into().unwrap();
259 status_mut_view.set_status_2(0x12);
260 assert_eq!(status_mut_view.get_status_2(), 0x12);
261 send(&status_mut_view);
262 }
263
264 #[test]
265 fn call_base_and_sub_methods() {
266 let mut owned = Packet::new(2, b"0123456".to_owned());
267 owned.set_raw_payload(b"xxxxxxx".to_owned());
268
269 {
270 let status_view: &StatusPacket = (&owned).try_into().unwrap();
271 status_view.get_status_2();
272 status_view.get_raw_payload();
273 }
274
275 let mut status_mut_view: &mut StatusPacket = (&mut owned).try_into().unwrap();
276 status_mut_view.get_status_2();
277 status_mut_view.get_raw_payload();
278 status_mut_view.set_status_2(0x34);
279
280 }
283
284 #[test]
285 fn create_from_immutable_ref() {
286 let v = vec![Packet::new(2, b"0123456".to_owned())];
287
288 for p in v.iter() {
289 let status_view: &StatusPacket = (&(*p)).try_into().unwrap();
290 status_view.get_status_2();
291 }
292 }
293
294 #[test]
295 fn use_owned_status() {
296 let p = Packet::new(2, b"0123456".to_owned());
297
298 let s: StatusPacket = p.try_into().unwrap();
299
300 swallow_status_packet(s);
301 }
302}