byteordered/
base.rs

1//! Base Endianness type module.
2
3use byteorder::{BigEndian, ByteOrder, LittleEndian, NativeEndian, ReadBytesExt, WriteBytesExt};
4use std::default::Default;
5use std::io::{Read, Result as IoResult, Write};
6use std::marker::PhantomData;
7
8/// Trait for any type which has an opposite type. This is used to convert
9/// immaterial types representing "little endian" into "big endian" and vice
10/// versa.
11pub trait HasOpposite: private::Sealed {
12    type Opposite;
13}
14
15impl HasOpposite for LittleEndian {
16    type Opposite = BigEndian;
17}
18
19impl HasOpposite for BigEndian {
20    type Opposite = LittleEndian;
21}
22
23/// Trait for identifying whether a type is representative of the system's
24/// native byte order.
25pub trait StaticNative: private::Sealed {
26    /// Checks whether this type represents the system's native endianness.
27    fn is_native() -> bool;
28}
29
30impl StaticNative for NativeEndian {
31    fn is_native() -> bool {
32        true
33    }
34}
35
36#[cfg(target_endian = "little")]
37impl StaticNative for BigEndian {
38    fn is_native() -> bool {
39        false
40    }
41}
42
43#[cfg(target_endian = "big")]
44impl StaticNative for LittleEndian {
45    fn is_native() -> bool {
46        false
47    }
48}
49
50/// General trait for types that can
51/// serialize and deserialize bytes in some byte order.
52///
53/// The trait roughly resembles [`byteorder::ByteOrder`],
54/// with the exception that it is implemented for material types,
55/// which are also `Copy`,
56/// and all methods receive `self`.
57/// This makes it possible to embed byte order information to a reader or writer
58/// by composition,
59/// which is done by [`ByteOrdered`].
60///
61/// [`byteorder::ByteOrder`]: https://docs.rs/byteorder/*/byteorder/trait.ByteOrder.html
62/// [`ByteOrdered`]: struct.ByteOrdered.html
63pub trait Endian: Copy + private::Sealed {
64    /// A type which can represent a byte order that is opposite to this one.
65    type Opposite;
66
67    /// Checks whether this value represents the system's native endianness.
68    fn is_native(self) -> bool;
69
70    /// Converts the receiver into its opposite.
71    fn into_opposite(self) -> Self::Opposite;
72
73    /// Reads a signed 16 bit integer from the given reader.
74    ///
75    /// # Errors
76    ///
77    /// This method returns the same errors as [`Read::read_exact`].
78    ///
79    /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact
80    fn read_i16<R>(self, reader: R) -> IoResult<i16>
81    where
82        R: Read;
83
84    /// Reads a sequence of signed 16 bit integers from the given reader.
85    ///
86    /// The given buffer is either filled completely or an error is returned.
87    /// If an error is returned,
88    /// the contents of `dst` are unspecified.
89    ///
90    /// # Errors
91    ///
92    /// This method returns the same errors as [`Read::read_exact`].
93    ///
94    /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact
95    fn read_i16_into<R>(self, mut reader: R, dst: &mut [i16]) -> IoResult<()>
96    where
97        R: Read,
98    {
99        for e in dst.iter_mut() {
100            *e = self.read_i16(&mut reader)?;
101        }
102        Ok(())
103    }
104
105    /// Reads an unsigned 16 bit integer from the given reader.
106    ///
107    /// # Errors
108    ///
109    /// This method returns the same errors as [`Read::read_exact`].
110    ///
111    /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact
112    fn read_u16<R>(self, reader: R) -> IoResult<u16>
113    where
114        R: Read;
115
116    /// Reads a sequence of unsigned 16 bit integers from the given reader.
117    ///
118    /// The given buffer is either filled completely or an error is returned.
119    /// If an error is returned,
120    /// the contents of `dst` are unspecified.
121    ///
122    /// # Errors
123    ///
124    /// This method returns the same errors as [`Read::read_exact`].
125    ///
126    /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact
127    fn read_u16_into<R>(self, mut reader: R, dst: &mut [u16]) -> IoResult<()>
128    where
129        R: Read,
130    {
131        for e in dst.iter_mut() {
132            *e = self.read_u16(&mut reader)?;
133        }
134        Ok(())
135    }
136
137    /// Reads a signed 32 bit integer from the given reader.
138    ///
139    /// # Errors
140    ///
141    /// This method returns the same errors as [`Read::read_exact`].
142    ///
143    /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact
144    fn read_i32<R>(self, reader: R) -> IoResult<i32>
145    where
146        R: Read;
147
148    /// Reads a sequence of signed 32 bit integers from the given reader.
149    ///
150    /// The given buffer is either filled completely or an error is returned.
151    /// If an error is returned,
152    /// the contents of `dst` are unspecified.
153    ///
154    /// # Errors
155    ///
156    /// This method returns the same errors as [`Read::read_exact`].
157    ///
158    /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact
159    fn read_i32_into<R>(self, mut reader: R, dst: &mut [i32]) -> IoResult<()>
160    where
161        R: Read,
162    {
163        for e in dst.iter_mut() {
164            *e = self.read_i32(&mut reader)?;
165        }
166        Ok(())
167    }
168
169    /// Reads an unsigned 32 bit integer from the given reader.
170    ///
171    /// # Errors
172    ///
173    /// This method returns the same errors as [`Read::read_exact`].
174    ///
175    /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact
176    fn read_u32<R>(self, reader: R) -> IoResult<u32>
177    where
178        R: Read;
179
180    /// Reads a sequence of unsigned 32 bit integers from the given reader.
181    ///
182    /// The given buffer is either filled completely or an error is returned.
183    /// If an error is returned,
184    /// the contents of `dst` are unspecified.
185    ///
186    /// # Errors
187    ///
188    /// This method returns the same errors as [`Read::read_exact`].
189    ///
190    /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact
191    fn read_u32_into<R>(self, mut reader: R, dst: &mut [u32]) -> IoResult<()>
192    where
193        R: Read,
194    {
195        for e in dst.iter_mut() {
196            *e = self.read_u32(&mut reader)?;
197        }
198        Ok(())
199    }
200
201    /// Reads a signed 64 bit integer from the given reader.
202    ///
203    /// # Errors
204    ///
205    /// This method returns the same errors as [`Read::read_exact`].
206    ///
207    /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact
208    fn read_i64<R>(self, reader: R) -> IoResult<i64>
209    where
210        R: Read;
211
212    /// Reads a sequence of signed 64 bit integers from the given reader.
213    ///
214    /// The given buffer is either filled completely or an error is returned.
215    /// If an error is returned,
216    /// the contents of `dst` are unspecified.
217    ///
218    /// # Errors
219    ///
220    /// This method returns the same errors as [`Read::read_exact`].
221    ///
222    /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact
223    fn read_i64_into<R>(self, mut reader: R, dst: &mut [i64]) -> IoResult<()>
224    where
225        R: Read,
226    {
227        for e in dst.iter_mut() {
228            *e = self.read_i64(&mut reader)?;
229        }
230        Ok(())
231    }
232
233    /// Reads an unsigned 64 bit integer from the given reader.
234    ///
235    /// # Errors
236    ///
237    /// This method returns the same errors as [`Read::read_exact`].
238    ///
239    /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact
240    fn read_u64<R>(self, reader: R) -> IoResult<u64>
241    where
242        R: Read;
243
244    /// Reads a sequence of unsigned 64 bit integers from the given reader.
245    ///
246    /// The given buffer is either filled completely or an error is returned.
247    /// If an error is returned,
248    /// the contents of `dst` are unspecified.
249    ///
250    /// # Errors
251    ///
252    /// This method returns the same errors as [`Read::read_exact`].
253    ///
254    /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact
255    fn read_u64_into<R>(self, mut reader: R, dst: &mut [u64]) -> IoResult<()>
256    where
257        R: Read,
258    {
259        for e in dst.iter_mut() {
260            *e = self.read_u64(&mut reader)?;
261        }
262        Ok(())
263    }
264
265    /// Reads a signed 128 bit integer from the given reader.
266    ///
267    /// # Errors
268    ///
269    /// This method returns the same errors as [`Read::read_exact`].
270    ///
271    /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact
272    fn read_i128<R>(self, reader: R) -> IoResult<i128>
273    where
274        R: Read;
275
276    /// Reads a sequence of signed 128 bit integers from the given reader.
277    ///
278    /// The given buffer is either filled completely or an error is returned.
279    /// If an error is returned,
280    /// the contents of `dst` are unspecified.
281    ///
282    /// # Errors
283    ///
284    /// This method returns the same errors as [`Read::read_exact`].
285    ///
286    /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact
287    fn read_i128_into<R>(self, mut reader: R, dst: &mut [i128]) -> IoResult<()>
288    where
289        R: Read,
290    {
291        for e in dst.iter_mut() {
292            *e = self.read_i128(&mut reader)?;
293        }
294        Ok(())
295    }
296
297    /// Reads an unsigned 128 bit integer from the given reader.
298    ///
299    /// # Errors
300    ///
301    /// This method returns the same errors as [`Read::read_exact`].
302    ///
303    /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact
304    fn read_u128<R>(self, reader: R) -> IoResult<u128>
305    where
306        R: Read;
307
308    /// Reads a sequence of unsigned 128 bit integers from the given reader.
309    ///
310    /// The given buffer is either filled completely or an error is returned.
311    /// If an error is returned,
312    /// the contents of `dst` are unspecified.
313    ///
314    /// # Errors
315    ///
316    /// This method returns the same errors as [`Read::read_exact`].
317    ///
318    /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact
319    fn read_u128_into<R>(self, mut reader: R, dst: &mut [u128]) -> IoResult<()>
320    where
321        R: Read,
322    {
323        for e in dst.iter_mut() {
324            *e = self.read_u128(&mut reader)?;
325        }
326        Ok(())
327    }
328
329    /// Reads a IEEE754 single-precision (4 bytes) floating point number from
330    /// the given reader.
331    ///
332    /// # Errors
333    ///
334    /// This method returns the same errors as [`Read::read_exact`].
335    ///
336    /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact
337    fn read_f32<R>(self, reader: R) -> IoResult<f32>
338    where
339        R: Read;
340
341    /// Reads a sequence of IEEE754 single-precision (4 bytes) floating point numbers
342    /// from the given reader.
343    ///
344    /// The given buffer is either filled completely or an error is returned.
345    /// If an error is returned,
346    /// the contents of `dst` are unspecified.
347    ///
348    /// # Errors
349    ///
350    /// This method returns the same errors as [`Read::read_exact`].
351    ///
352    /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact
353    fn read_f32_into<R>(self, mut reader: R, dst: &mut [f32]) -> IoResult<()>
354    where
355        R: Read,
356    {
357        for e in dst.iter_mut() {
358            *e = self.read_f32(&mut reader)?;
359        }
360        Ok(())
361    }
362
363    /// Reads a IEEE754 double-precision (8 bytes) floating point number from
364    /// the given reader.
365    ///
366    /// # Errors
367    ///
368    /// This method returns the same errors as [`Read::read_exact`].
369    ///
370    /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact
371    fn read_f64<R>(self, reader: R) -> IoResult<f64>
372    where
373        R: Read;
374
375    /// Reads a sequence of IEEE754 double-precision (8 bytes) floating point numbers
376    /// from the given reader.
377    ///
378    /// The given buffer is either filled completely or an error is returned.
379    /// If an error is returned,
380    /// the contents of `dst` are unspecified.
381    ///
382    /// # Errors
383    ///
384    /// This method returns the same errors as [`Read::read_exact`].
385    ///
386    /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact
387    fn read_f64_into<R>(self, mut reader: R, dst: &mut [f64]) -> IoResult<()>
388    where
389        R: Read,
390    {
391        for e in dst.iter_mut() {
392            *e = self.read_f64(&mut reader)?;
393        }
394        Ok(())
395    }
396
397    /// Writes a signed 16 bit integer to the given writer.
398    ///
399    /// # Errors
400    ///
401    /// This method returns the same errors as [`Write::write_all`].
402    ///
403    /// [`Write::write_all`]: https://doc.rust-lang.org/std/io/trait.Write.html#method.write_all
404    fn write_i16<W>(self, writer: W, v: i16) -> IoResult<()>
405    where
406        W: Write;
407
408    /// Writes an unsigned 16 bit integer to the given writer.
409    ///
410    /// # Errors
411    ///
412    /// This method returns the same errors as [`Write::write_all`].
413    ///
414    /// [`Write::write_all`]: https://doc.rust-lang.org/std/io/trait.Write.html#method.write_all
415    fn write_u16<W>(self, writer: W, v: u16) -> IoResult<()>
416    where
417        W: Write;
418
419    /// Writes a signed 32 bit integer to the given writer.
420    ///
421    /// # Errors
422    ///
423    /// This method returns the same errors as [`Write::write_all`].
424    ///
425    /// [`Write::write_all`]: https://doc.rust-lang.org/std/io/trait.Write.html#method.write_all
426    fn write_i32<W>(self, writer: W, v: i32) -> IoResult<()>
427    where
428        W: Write;
429
430    /// Writes an unsigned 32 bit integer to the given writer.
431    ///
432    /// # Errors
433    ///
434    /// This method returns the same errors as [`Write::write_all`].
435    ///
436    /// [`Write::write_all`]: https://doc.rust-lang.org/std/io/trait.Write.html#method.write_all
437    fn write_u32<W>(self, writer: W, v: u32) -> IoResult<()>
438    where
439        W: Write;
440
441    /// Writes a signed 64 bit integer to the given writer.
442    ///
443    /// # Errors
444    ///
445    /// This method returns the same errors as [`Write::write_all`].
446    ///
447    /// [`Write::write_all`]: https://doc.rust-lang.org/std/io/trait.Write.html#method.write_all
448    fn write_i64<W>(self, writer: W, v: i64) -> IoResult<()>
449    where
450        W: Write;
451
452    /// Writes an unsigned 64 bit integer to the given writer.
453    ///
454    /// # Errors
455    ///
456    /// This method returns the same errors as [`Write::write_all`].
457    ///
458    /// [`Write::write_all`]: https://doc.rust-lang.org/std/io/trait.Write.html#method.write_all
459    fn write_u64<W>(self, writer: W, v: u64) -> IoResult<()>
460    where
461        W: Write;
462
463    /// Writes a signed 128 bit integer to the given writer.
464    ///
465    /// # Errors
466    ///
467    /// This method returns the same errors as [`Write::write_all`].
468    ///
469    /// [`Write::write_all`]: https://doc.rust-lang.org/std/io/trait.Write.html#method.write_all
470    fn write_i128<W>(self, writer: W, v: i128) -> IoResult<()>
471    where
472        W: Write;
473
474    /// Writes an unsigned 128 bit integer to the given writer.
475    ///
476    /// # Errors
477    ///
478    /// This method returns the same errors as [`Write::write_all`].
479    ///
480    /// [`Write::write_all`]: https://doc.rust-lang.org/std/io/trait.Write.html#method.write_all
481    fn write_u128<W>(self, writer: W, v: u128) -> IoResult<()>
482    where
483        W: Write;
484
485    /// Writes a IEEE754 single-precision (4 bytes) floating point number to
486    /// the given writer.
487    ///
488    /// # Errors
489    ///
490    /// This method returns the same errors as [`Write::write_all`].
491    ///
492    /// [`Write::write_all`]: https://doc.rust-lang.org/std/io/trait.Write.html#method.write_all
493    fn write_f32<W>(self, writer: W, v: f32) -> IoResult<()>
494    where
495        W: Write;
496
497    /// Writes a IEEE754 double-precision (8 bytes) floating point number to
498    /// the given writer.
499    ///
500    /// # Errors
501    ///
502    /// This method returns the same errors as [`Write::write_all`].
503    ///
504    /// [`Write::write_all`]: https://doc.rust-lang.org/std/io/trait.Write.html#method.write_all
505    fn write_f64<W>(self, writer: W, v: f64) -> IoResult<()>
506    where
507        W: Write;
508}
509
510/// A data type representing a byte order known in compile time.
511/// Unlike the types provided in `byteorder`, this type can be constructed.
512///
513/// The parameter type `E` can be one of either [`byteorder::BigEndian`][be]
514/// or [`byteorder::LittleEndian`][le].
515///
516/// [be]: https://docs.rs/byteorder/*/byteorder/enum.BigEndian.html
517/// [le]: https://docs.rs/byteorder/*/byteorder/enum.LittleEndian.html
518#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)]
519pub struct StaticEndianness<E>(PhantomData<E>);
520
521impl<E> Default for StaticEndianness<E> {
522    #[inline]
523    fn default() -> Self {
524        StaticEndianness::new()
525    }
526}
527
528impl<E> StaticEndianness<E> {
529    /// Constructor for a static endianness.
530    #[inline]
531    pub fn new() -> Self {
532        StaticEndianness(PhantomData)
533    }
534}
535
536impl StaticEndianness<NativeEndian> {
537    /// Constructor for native endianness.
538    #[inline]
539    pub fn native() -> Self {
540        StaticEndianness::new()
541    }
542}
543
544impl PartialEq<StaticEndianness<LittleEndian>> for StaticEndianness<BigEndian> {
545    #[inline]
546    fn eq(&self, _: &StaticEndianness<LittleEndian>) -> bool {
547        false
548    }
549}
550
551impl PartialEq<StaticEndianness<BigEndian>> for StaticEndianness<LittleEndian> {
552    #[inline]
553    fn eq(&self, _: &StaticEndianness<BigEndian>) -> bool {
554        false
555    }
556}
557
558impl PartialEq<Endianness> for StaticEndianness<BigEndian> {
559    #[inline]
560    fn eq(&self, e: &Endianness) -> bool {
561        *e == Endianness::Big
562    }
563}
564
565impl PartialEq<Endianness> for StaticEndianness<LittleEndian> {
566    #[inline]
567    fn eq(&self, e: &Endianness) -> bool {
568        *e == Endianness::Little
569    }
570}
571
572impl<E> HasOpposite for StaticEndianness<E>
573where
574    E: HasOpposite,
575{
576    type Opposite = StaticEndianness<E::Opposite>;
577}
578
579/// Private macro for endiannesses known at compile time,
580/// which implements a `read_*` method
581/// by delegating a call to the same method on `ReadBytesExt`.
582macro_rules! fn_static_endianness_read {
583    ($method:ident, $e:ty, $out:ty) => {
584        #[inline]
585        fn $method<S>(self, mut src: S) -> IoResult<$out>
586        where
587            S: Read,
588        {
589            src.$method::<$e>()
590        }
591    };
592}
593
594/// Private macro for endiannesses known at compile time,
595/// which implements a `read_*_into` method
596/// by delegating a call to the same method on `ReadBytesExt`.
597macro_rules! fn_static_endianness_read_into {
598    ($method:ident, $e:ty, $out:ty) => {
599        #[inline]
600        fn $method<S>(self, mut src: S, dst: &mut [$out]) -> IoResult<()>
601        where
602            S: Read,
603        {
604            src.$method::<$e>(dst)
605        }
606    };
607}
608
609/// Private macro for endiannesses known at compile time,
610/// which implements a `write_*` method
611/// by delegating a call to the same method on `WriteBytesExt`.
612macro_rules! fn_static_endianness_write {
613    ($method:ident, $e:ty, $out:ty) => {
614        #[inline]
615        fn $method<W>(self, mut src: W, x: $out) -> IoResult<()>
616        where
617            W: Write,
618        {
619            src.$method::<$e>(x)
620        }
621    };
622}
623
624impl<E> Endian for StaticEndianness<E>
625where
626    E: HasOpposite,
627    E: StaticNative,
628    E: ByteOrder,
629{
630    type Opposite = StaticEndianness<E::Opposite>;
631
632    #[inline]
633    fn into_opposite(self) -> Self::Opposite {
634        StaticEndianness(PhantomData)
635    }
636
637    #[inline]
638    fn is_native(self) -> bool {
639        E::is_native()
640    }
641
642    fn_static_endianness_read!(read_i16, E, i16);
643    fn_static_endianness_read!(read_u16, E, u16);
644    fn_static_endianness_read!(read_i32, E, i32);
645    fn_static_endianness_read!(read_u32, E, u32);
646    fn_static_endianness_read!(read_i64, E, i64);
647    fn_static_endianness_read!(read_u64, E, u64);
648    fn_static_endianness_read!(read_i128, E, i128);
649    fn_static_endianness_read!(read_u128, E, u128);
650    fn_static_endianness_read!(read_f32, E, f32);
651    fn_static_endianness_read!(read_f64, E, f64);
652
653    fn_static_endianness_read_into!(read_i16_into, E, i16);
654    fn_static_endianness_read_into!(read_u16_into, E, u16);
655    fn_static_endianness_read_into!(read_i32_into, E, i32);
656    fn_static_endianness_read_into!(read_u32_into, E, u32);
657    fn_static_endianness_read_into!(read_i64_into, E, i64);
658    fn_static_endianness_read_into!(read_u64_into, E, u64);
659    fn_static_endianness_read_into!(read_i128_into, E, i128);
660    fn_static_endianness_read_into!(read_u128_into, E, u128);
661    fn_static_endianness_read_into!(read_f32_into, E, f32);
662    fn_static_endianness_read_into!(read_f64_into, E, f64);
663
664    fn_static_endianness_write!(write_i16, E, i16);
665    fn_static_endianness_write!(write_u16, E, u16);
666    fn_static_endianness_write!(write_i32, E, i32);
667    fn_static_endianness_write!(write_u32, E, u32);
668    fn_static_endianness_write!(write_i64, E, i64);
669    fn_static_endianness_write!(write_u64, E, u64);
670    fn_static_endianness_write!(write_i128, E, i128);
671    fn_static_endianness_write!(write_u128, E, u128);
672    fn_static_endianness_write!(write_f32, E, f32);
673    fn_static_endianness_write!(write_f64, E, f64);
674}
675
676/// Enumerate for materializing
677/// the two kinds of machine byte order supported by Rust
678/// in a dynamic fashion.
679/// That is,
680/// the information of whether to read or write data
681/// in Little Endian or in Big Endian
682/// is resolved at run time by observing this value.
683///
684/// Using this type as the generic endianness type `E` in a `ByteOrdered`
685/// is useful when this information can only be retrieved
686/// from a source that is unknown to the compiler.
687#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy, PartialOrd, Ord)]
688pub enum Endianness {
689    /// Little Endian
690    Little,
691    /// Big Endian
692    Big,
693}
694
695impl From<StaticEndianness<LittleEndian>> for Endianness {
696    #[inline]
697    fn from(_: StaticEndianness<LittleEndian>) -> Self {
698        Endianness::Little
699    }
700}
701
702impl From<StaticEndianness<BigEndian>> for Endianness {
703    #[inline]
704    fn from(_: StaticEndianness<BigEndian>) -> Self {
705        Endianness::Big
706    }
707}
708
709impl PartialEq<StaticEndianness<BigEndian>> for Endianness {
710    #[inline]
711    fn eq(&self, _: &StaticEndianness<BigEndian>) -> bool {
712        *self == Endianness::Big
713    }
714}
715
716impl PartialEq<StaticEndianness<LittleEndian>> for Endianness {
717    #[inline]
718    fn eq(&self, _: &StaticEndianness<LittleEndian>) -> bool {
719        *self == Endianness::Little
720    }
721}
722
723/// Private macro for endiannesses known at run time,
724/// which implements a `read_*` method
725/// by delegating a call to the same method on `ReadBytesExt`.
726macro_rules! fn_runtime_endianness_read {
727    ($method:ident, $out:ty) => {
728        #[inline]
729        fn $method<S>(self, mut src: S) -> IoResult<$out>
730        where
731            S: Read,
732        {
733            match self {
734                Endianness::Little => src.$method::<LittleEndian>(),
735                Endianness::Big => src.$method::<BigEndian>(),
736            }
737        }
738    };
739}
740
741/// Private macro for endiannesses known at run time,
742/// which implements a `read_*_into` method
743/// by delegating a call to the same method on `ReadBytesExt`.
744macro_rules! fn_runtime_endianness_read_into {
745    ($method:ident, $out:ty) => {
746        #[inline]
747        fn $method<S>(self, mut src: S, dst: &mut [$out]) -> IoResult<()>
748        where
749            S: Read,
750        {
751            match self {
752                Endianness::Little => src.$method::<LittleEndian>(dst),
753                Endianness::Big => src.$method::<BigEndian>(dst),
754            }
755        }
756    };
757}
758
759/// Private macro for endiannesses known at run time,
760/// which implements a `write_*` method
761/// by delegating a call to the same method on `WriteBytesExt`.
762macro_rules! fn_runtime_endianness_write {
763    ($method:ident, $i:ty) => {
764        #[inline]
765        fn $method<S>(self, mut src: S, v: $i) -> IoResult<()>
766        where
767            S: Write,
768        {
769            match self {
770                Endianness::Little => src.$method::<LittleEndian>(v),
771                Endianness::Big => src.$method::<BigEndian>(v),
772            }
773        }
774    };
775}
776
777impl HasOpposite for Endianness {
778    type Opposite = Self;
779}
780
781impl Endian for Endianness {
782    type Opposite = Self;
783
784    #[inline]
785    fn into_opposite(self) -> Self::Opposite {
786        self.to_opposite()
787    }
788
789    #[inline]
790    fn is_native(self) -> bool {
791        self == Endianness::native()
792    }
793
794    fn_runtime_endianness_read!(read_i16, i16);
795    fn_runtime_endianness_read!(read_u16, u16);
796    fn_runtime_endianness_read!(read_i32, i32);
797    fn_runtime_endianness_read!(read_u32, u32);
798    fn_runtime_endianness_read!(read_i64, i64);
799    fn_runtime_endianness_read!(read_u64, u64);
800    fn_runtime_endianness_read!(read_f32, f32);
801    fn_runtime_endianness_read!(read_f64, f64);
802    fn_runtime_endianness_read!(read_i128, i128);
803    fn_runtime_endianness_read!(read_u128, u128);
804
805    fn_runtime_endianness_read_into!(read_i16_into, i16);
806    fn_runtime_endianness_read_into!(read_u16_into, u16);
807    fn_runtime_endianness_read_into!(read_i32_into, i32);
808    fn_runtime_endianness_read_into!(read_u32_into, u32);
809    fn_runtime_endianness_read_into!(read_i64_into, i64);
810    fn_runtime_endianness_read_into!(read_u64_into, u64);
811    fn_runtime_endianness_read_into!(read_f32_into, f32);
812    fn_runtime_endianness_read_into!(read_f64_into, f64);
813    fn_runtime_endianness_read_into!(read_i128_into, i128);
814    fn_runtime_endianness_read_into!(read_u128_into, u128);
815
816    fn_runtime_endianness_write!(write_i16, i16);
817    fn_runtime_endianness_write!(write_u16, u16);
818    fn_runtime_endianness_write!(write_i32, i32);
819    fn_runtime_endianness_write!(write_u32, u32);
820    fn_runtime_endianness_write!(write_i64, i64);
821    fn_runtime_endianness_write!(write_u64, u64);
822    fn_runtime_endianness_write!(write_f32, f32);
823    fn_runtime_endianness_write!(write_f64, f64);
824    fn_runtime_endianness_write!(write_i128, i128);
825    fn_runtime_endianness_write!(write_u128, u128);
826}
827
828impl Endianness {
829    /// Obtains this system's native endianness.
830    ///
831    /// On this platform, the function returns `Endianness::Little`.
832    #[cfg(target_endian = "little")]
833    #[inline]
834    pub fn native() -> Self {
835        Endianness::Little
836    }
837
838    /// Obtains this system's native endianness.
839    ///
840    /// On this platform, the function returns `Endianness::Big`.
841    #[cfg(target_endian = "big")]
842    #[inline]
843    pub fn native() -> Self {
844        Endianness::Big
845    }
846
847    /// Obtains _Little Endian_ if and only if the given value is `true`.
848    ///
849    /// # Examples
850    ///
851    /// ```
852    /// # use byteordered::{Endian, Endianness};
853    /// let data: &[u8] = &[4, 1];
854    /// let e = Endianness::le_iff(2 + 2 == 4);
855    /// assert_eq!(e.read_u16(data).unwrap(), 260);
856    ///
857    /// let e = Endianness::le_iff(2 + 2 >= 5);
858    /// assert_eq!(e.read_u16(data).unwrap(), 1025);
859    /// ```
860    #[inline]
861    pub fn le_iff(e: bool) -> Self {
862        if e {
863            Endianness::Little
864        } else {
865            Endianness::Big
866        }
867    }
868
869    /// Obtains _Big Endian_ if and only if the given value is `true`.
870    ///
871    /// Examples
872    ///
873    /// ```
874    /// # use byteordered::Endianness;
875    /// assert_eq!(Endianness::be_iff(2 + 2 == 4), Endianness::Big);
876    /// assert_eq!(Endianness::be_iff(2 + 2 >= 5), Endianness::Little);
877    /// ```
878    #[inline]
879    pub fn be_iff(e: bool) -> Self {
880        if e {
881            Endianness::Big
882        } else {
883            Endianness::Little
884        }
885    }
886
887    /// Obtains the opposite endianness: Little Endian returns Big Endian and vice versa.
888    #[inline]
889    pub fn to_opposite(self) -> Self {
890        if self == Endianness::Little {
891            Endianness::Big
892        } else {
893            Endianness::Little
894        }
895    }
896}
897
898mod private {
899    use super::{Endianness, StaticEndianness};
900    use byteorder::{BigEndian, LittleEndian};
901    pub trait Sealed {}
902
903    impl Sealed for LittleEndian {}
904    impl Sealed for BigEndian {}
905    impl<T> Sealed for StaticEndianness<T> {}
906    impl Sealed for Endianness {}
907}
908
909#[cfg(test)]
910mod tests {
911    use super::*;
912    /// the test bytes for testing integer type reading
913    static TEST_BYTES: &'static [u8] = &[0x12, 0x34, 0x56, 0x78, 0x21, 0x43, 0x65, 0x87];
914
915    /// the test bytes as a single u64 in little endian
916    static TEST_U64DATA_LE: &'static [u64] = &[0x87654321_78563412];
917    /// the test bytes as a single u64 in big endian
918    static TEST_U64DATA_BE: &'static [u64] = &[0x12345678_21436587];
919
920    #[test]
921    fn test_read_u64() {
922        let mut data = TEST_BYTES;
923        let e = Endianness::Little;
924        let words = [e.read_u64(&mut data).unwrap()];
925        assert_eq!(words, TEST_U64DATA_LE);
926
927        let mut data = TEST_BYTES;
928        let e = Endianness::Big;
929        let words = [e.read_u64(&mut data).unwrap()];
930        assert_eq!(words, TEST_U64DATA_BE);
931    }
932
933    /// the test bytes as two u32s in little endian
934    static TEST_U32DATA_LE: &'static [u32] = &[0x7856_3412, 0x8765_4321];
935    /// the test bytes as two u32s in big endian
936    static TEST_U32DATA_BE: &'static [u32] = &[0x1234_5678, 0x2143_6587];
937
938    #[test]
939    fn test_read_u32() {
940        let mut data = TEST_BYTES;
941        let e = Endianness::Little;
942        let words = [
943            e.read_u32(&mut data).unwrap(),
944            e.read_u32(&mut data).unwrap(),
945        ];
946        assert_eq!(words, TEST_U32DATA_LE);
947
948        let mut data = TEST_BYTES;
949        let e = Endianness::Big;
950        let words = [
951            e.read_u32(&mut data).unwrap(),
952            e.read_u32(&mut data).unwrap(),
953        ];
954        assert_eq!(words, TEST_U32DATA_BE);
955    }
956
957    /// the test bytes as four u16s in little endian
958    static TEST_U16DATA_LE: &'static [u16] = &[0x3412, 0x7856, 0x4321, 0x8765];
959    /// the test bytes as four u16s in big endian
960    static TEST_U16DATA_BE: &'static [u16] = &[0x1234, 0x5678, 0x2143, 0x6587];
961
962    #[test]
963    fn test_read_u16() {
964        let mut data = TEST_BYTES;
965        let e = Endianness::Little;
966        let words = [
967            e.read_u16(&mut data).unwrap(),
968            e.read_u16(&mut data).unwrap(),
969            e.read_u16(&mut data).unwrap(),
970            e.read_u16(&mut data).unwrap(),
971        ];
972        assert_eq!(words, TEST_U16DATA_LE);
973
974        let mut data = TEST_BYTES;
975        let e = Endianness::Big;
976        let words = [
977            e.read_u16(&mut data).unwrap(),
978            e.read_u16(&mut data).unwrap(),
979            e.read_u16(&mut data).unwrap(),
980            e.read_u16(&mut data).unwrap(),
981        ];
982        assert_eq!(words, TEST_U16DATA_BE);
983    }
984
985    #[test]
986    fn test_read_u16_into() {
987        let data = TEST_BYTES;
988
989        let e = Endianness::Little;
990        let mut words = [0; 4];
991        e.read_u16_into(&mut &data[..], &mut words).unwrap();
992        assert_eq!(words, TEST_U16DATA_LE);
993
994        let e = Endianness::Big;
995        let mut words = [0; 4];
996        e.read_u16_into(&mut &data[..], &mut words).unwrap();
997        assert_eq!(words, TEST_U16DATA_BE);
998    }
999
1000    #[test]
1001    fn test_read_u32_into() {
1002        let data = TEST_BYTES;
1003
1004        let e = Endianness::Little;
1005        let mut words = [0; 2];
1006        e.read_u32_into(&mut &data[..], &mut words).unwrap();
1007        assert_eq!(words, TEST_U32DATA_LE);
1008
1009        let e = Endianness::Big;
1010        let mut words = [0; 2];
1011        e.read_u32_into(&mut &data[..], &mut words).unwrap();
1012        assert_eq!(words, TEST_U32DATA_BE);
1013    }
1014
1015    #[test]
1016    fn test_native_is_le() {
1017        if cfg!(target_endian = "little") {
1018            assert_eq!(Endianness::native(), Endianness::Little);
1019        } else if cfg!(target_endian = "big") {
1020            assert_eq!(Endianness::native(), Endianness::Big);
1021        } else {
1022            unreachable!();
1023        }
1024    }
1025
1026    // TODO test writing
1027}