Repository: BurntSushi/byteorder (language: rust)

Issue:
Add impls for all of the builtin traits to LittleEndian and BigEndian and make ByteOrder also require those impls
Right now, making something compile-time generic over endianness is a huge pain:

``` rust
extern crate byteorder;
use byteorder::{ByteOrder, LittleEndian};

use std::marker::PhantomData;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
struct EndianBuf<'a, Endian>(&'a [u8], PhantomData<Endian>) where Endian: ByteOrder;

impl<'a, Endian> EndianBuf<'a, Endian> where Endian: ByteOrder {
    fn new(buf: &'a [u8]) -> EndianBuf<'a, Endian> {
        EndianBuf(buf, PhantomData)
    }
}

fn main() {
    let buf = [1,2,3,4,5,6];

    let a = EndianBuf::<LittleEndian>::new(&buf);
    let b = EndianBuf::<LittleEndian>::new(&buf);

    // Compiler error regarding this line!
    assert_eq!(a, b);
}
```

If you do `rustc -Z unstable-options --pretty expanded endian_buf.rs`, you will see this:

``` rust
#[automatically_derived]
#[allow(unused_qualifications)]
impl <'a, Endian: ::std::clone::Clone> ::std::clone::Clone for EndianBuf<'a, Endian>
    where Endian: ByteOrder 
{
    // ...snip...
}
```

The derived impls require that the type traits also implement the trait.

If `ByteOrder` implied `Eq`, `Clone`, `Copy`, etc... the problems would go away. Arguably, this is a bug in the `#[derive(Foo)]` expansion code for not understanding `PhantomData`, but adding this would work around that bug.

Since one can't even instantiate `BigEndian` or `LittleEndian`, all the impls could be `unreachable!()`.

Would you be willing to accept a patch that does this?



Discussion / hints:
@fitzgen Sorry for not responding earlier, but I think your suggestion sounds fine. I don't think it will cause any massive breaking changes either (because I don't really expect any impls of `ByteOrder` other than what's defined in this crate).


Fix patch:
diff --git a/src/lib.rs b/src/lib.rs
index a25bab6..82173b9 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -46,6 +46,8 @@ assert_eq!(wtr, vec![5, 2, 0, 3]);
 #[cfg(feature = "std")]
 extern crate core;
 
+use core::fmt::Debug;
+use core::hash::Hash;
 use core::mem::transmute;
 use core::ptr::copy_nonoverlapping;
 
@@ -118,7 +120,8 @@ fn pack_size(n: u64) -> usize {
 /// BigEndian::write_i16(&mut buf, -50_000);
 /// assert_eq!(-50_000, BigEndian::read_i16(&buf));
 /// ```
-pub trait ByteOrder {
+pub trait ByteOrder
+    : Clone + Copy + Debug + Default + Eq + Hash + Ord + PartialEq + PartialOrd {
     /// Reads an unsigned 16 bit integer from `buf`.
     ///
     /// Panics when `buf.len() < 2`.
@@ -264,13 +267,27 @@ pub trait ByteOrder {
 ///
 /// Note that this type has no value constructor. It is used purely at the
 /// type level.
-#[allow(missing_copy_implementations)] pub enum BigEndian {}
+#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+pub enum BigEndian {}
+
+impl Default for BigEndian {
+    fn default() -> BigEndian {
+        unreachable!()
+    }
+}
 
 /// Defines little-endian serialization.
 ///
 /// Note that this type has no value constructor. It is used purely at the
 /// type level.
-#[allow(missing_copy_implementations)] pub enum LittleEndian {}
+#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+pub enum LittleEndian {}
+
+impl Default for LittleEndian {
+    fn default() -> LittleEndian {
+        unreachable!()
+    }
+}
 
 /// Defines network byte order serialization.
 ///


Test patch: