1use std::io;
28use std::mem;
29
30pub trait Endian {
35 fn loadu16(buf: &[u8], from: usize) -> u16;
36 fn loadu32(buf: &[u8], from: usize) -> u32;
37 fn loadu64(buf: &[u8], from: usize) -> u64;
38 fn writeu16<W>(w: &mut W, num: u16) -> io::Result<()> where W: io::Write;
39 fn writeu32<W>(w: &mut W, num: u32) -> io::Result<()> where W: io::Write;
40 fn writeu64<W>(w: &mut W, num: u64) -> io::Result<()> where W: io::Write;
41}
42
43pub struct BigEndian;
44pub struct LittleEndian;
45
46macro_rules! generate_load {
47 ($name:ident, $int_type:ident, $from_func:ident) => (
48 fn $name(buf: &[u8], offset: usize) -> $int_type {
49 let mut num = [0u8; mem::size_of::<$int_type>()];
50 num.copy_from_slice(
51 &buf[offset .. offset + mem::size_of::<$int_type>()]);
52 $int_type::$from_func(num)
53 }
54 )
55}
56
57macro_rules! generate_write {
58 ($name:ident, $int_type:ident, $to_func:ident) => (
59 fn $name<W>(w: &mut W, num: $int_type)
60 -> io::Result<()> where W: io::Write {
61 let buf = num.$to_func();
62 w.write_all(&buf)
63 }
64 )
65}
66
67impl Endian for BigEndian {
68 generate_load!(loadu16, u16, from_be_bytes);
69 generate_load!(loadu32, u32, from_be_bytes);
70 generate_load!(loadu64, u64, from_be_bytes);
71 generate_write!(writeu16, u16, to_be_bytes);
72 generate_write!(writeu32, u32, to_be_bytes);
73 generate_write!(writeu64, u64, to_be_bytes);
74}
75
76impl Endian for LittleEndian {
77 generate_load!(loadu16, u16, from_le_bytes);
78 generate_load!(loadu32, u32, from_le_bytes);
79 generate_load!(loadu64, u64, from_le_bytes);
80 generate_write!(writeu16, u16, to_le_bytes);
81 generate_write!(writeu32, u32, to_le_bytes);
82 generate_write!(writeu64, u64, to_le_bytes);
83}
84
85#[cfg(test)]
86mod tests {
87 use super::*;
88
89 #[test]
90 fn loadu16() {
91 assert_eq!(BigEndian::loadu16(&[0x01, 0x02], 0), 0x0102);
92 assert_eq!(BigEndian::loadu16(&[0x01, 0x02, 0x03], 1), 0x0203);
93 assert_eq!(LittleEndian::loadu16(&[0x01, 0x02], 0), 0x0201);
94 assert_eq!(LittleEndian::loadu16(&[0x01, 0x02, 0x03], 1), 0x0302);
95 }
96
97 #[test]
98 fn loadu32() {
99 assert_eq!(BigEndian::loadu32(&[0x01, 0x02, 0x03, 0x04], 0),
100 0x01020304);
101 assert_eq!(BigEndian::loadu32(&[0x01, 0x02, 0x03, 0x04, 0x05], 1),
102 0x02030405);
103 assert_eq!(LittleEndian::loadu32(&[0x01, 0x02, 0x03, 0x04], 0),
104 0x04030201);
105 assert_eq!(LittleEndian::loadu32(&[0x01, 0x02, 0x03, 0x04, 0x05], 1),
106 0x05040302);
107 }
108
109 #[test]
110 fn loadu64() {
111 assert_eq!(BigEndian::loadu64(&[0x01, 0x02, 0x03, 0x04,
112 0x05, 0x06, 0x07, 0x08], 0),
113 0x0102030405060708);
114 assert_eq!(BigEndian::loadu64(&[0x01, 0x02, 0x03, 0x04, 0x05,
115 0x06, 0x07, 0x08, 0x09], 1),
116 0x0203040506070809);
117 assert_eq!(LittleEndian::loadu64(&[0x01, 0x02, 0x03, 0x04,
118 0x05, 0x06, 0x07, 0x08], 0),
119 0x0807060504030201);
120 assert_eq!(LittleEndian::loadu64(&[0x01, 0x02, 0x03, 0x04, 0x05,
121 0x06, 0x07, 0x08, 0x09], 1),
122 0x0908070605040302);
123 }
124
125 #[test]
126 fn writeu16() {
127 let mut buf = Vec::new();
128 BigEndian::writeu16(&mut buf, 0x0102).unwrap();
129 LittleEndian::writeu16(&mut buf, 0x0304).unwrap();
130 assert_eq!(buf, b"\x01\x02\x04\x03");
131 }
132
133 #[test]
134 fn writeu32() {
135 let mut buf = Vec::new();
136 BigEndian::writeu32(&mut buf, 0x01020304).unwrap();
137 LittleEndian::writeu32(&mut buf, 0x05060708).unwrap();
138 assert_eq!(buf, b"\x01\x02\x03\x04\x08\x07\x06\x05");
139 }
140
141 #[test]
142 fn writeu64() {
143 let mut buf = Vec::new();
144 BigEndian::writeu64(&mut buf, 0x0102030405060708).unwrap();
145 LittleEndian::writeu64(&mut buf, 0x090a0b0c0d0e0f10).unwrap();
146 assert_eq!(buf, b"\x01\x02\x03\x04\x05\x06\x07\x08\
147 \x10\x0f\x0e\x0d\x0c\x0b\x0a\x09");
148 }
149
150 #[test]
151 fn dispatch() {
152 fn dispatch_sub<E>(data: &[u8]) -> u16 where E: Endian {
153 E::loadu16(data, 0)
154 }
155 assert_eq!(dispatch_sub::<BigEndian>(&[0x01, 0x02]), 0x0102);
156 assert_eq!(dispatch_sub::<LittleEndian>(&[0x01, 0x02]), 0x0201);
157 }
158
159 #[test]
160 fn static_dispatch() {
161 fn dispatch_sub<E>(data: &[u8]) -> u16 where E: Endian {
162 E::loadu16(data, 0)
163 }
164 assert_eq!(dispatch_sub::<BigEndian> as *const (),
165 dispatch_sub::<BigEndian> as *const ());
166 assert_ne!(dispatch_sub::<BigEndian> as *const (),
167 dispatch_sub::<LittleEndian> as *const ());
168 }
169
170 #[test]
171 #[should_panic(expected = "index 3 out of range for slice of length 2")]
172 fn out_of_range() {
173 BigEndian::loadu16(&[0x01, 0x02], 1);
174 }
175
176 #[test]
180 #[should_panic(expected = "at")]
181 fn wrap_around() {
182 BigEndian::loadu16(&[0x01, 0x02], (-1isize) as usize);
183 }
184}