-
-
Notifications
You must be signed in to change notification settings - Fork 142
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Endianess
enum for runtime cases
#95
Comments
I would like to see use cases for this. How many people using |
I had to yesterday, but obviously I did it for generating the code, not in the actual run time. @Xion the |
I've found another interesting use case. When implementing (de)serialization manually (e.g. to support large numbers), this would be beneficial: trait ByteOrder {
const ENDIANESS: Endianess;
// The rest of the ByteOrder trait
}
fn read_from_bytes<BO: ByteOrder>(bytes: &[u8]) -> MyType {
// since the condition is const expr, the unreachable branch will be eliminated by compiler
if BO::ENDIANESS == Endianess::BigEndian {
// big endian implementation
} else {
// little endian implementation
}
} This allows more powerful generic programming. While run-time enum is not strictly necessary (one may use |
@Kixunil Could you elaborate a bit more on your use case? I don't think I understand it. |
Look at if BO::read_u16(&[42, 0]) == 42 {
// Big endian
} else {
// Little endian
} While this works, it's less straightforward, harder to understand and compiler must work harder to optimize it. At first I even thought it's impossible - only after more thinking I invented this hack. I wouldn't be surprised if someone else didn't see it and gave up. Is that more clear now? |
Are there any supported Rust targets that have runtime endianness? |
I would certainly be interested in this. My published My WIP library |
I have worked with a number of serialization frameworks which serialized in "natural order". This is rather handy as serializing an array of i32 is a single On the other hand, it means that at deserialization time the program needs to be able to handle both little and big endian files regardless of the endiannes of the actual hardware on which it runs. |
Maybe it's because I'm tired, but I've read this whole thread, and I still don't understand what folks are asking for here. I'd appreciate it if I wasn't sent to some crate to look at a nearly undocumented trait for a use case. Can someone lay this out for me in plain terms with an example? It would help to show the code that is needed today, and then to show the improvement if |
I can only speak for myself here, but a runtime endianness object struct FloatReader<R> {
order: Endianness,
src: R,
}
impl<R: Read> Iterator for FloatReader<R> {
type Item = IoResult<f32>;
fn next(&mut self) -> Option<IoResult<f32>> {
match self.order.read_f32(&mut self.src) {
Ok(v) => Some(Ok(v)),
Err(ref e) if e.kind() == ErrorKind::UnexpectedEof => None,
e @ Err(_) => Some(e),
}
}
} The decision of whether the floats are in LE or BE would be made on a producer of some sort, potentially from a header portion of the raw data. fn produce_reader<R: Read>(src: R) -> IoResult<FloatReader<R>> {
let e: Endianness = unimplemented!();
Ok(FloatReader {
order: e,
src,
});
} The main difference between what
In the end, we might consent with each of us having their own |
@Enet4 Thank you so much for taking the time to lay that out for me. That made it much easier to understand this ticket. :-) |
Add one more request to the pile. I have almost the same usecase — reading a data file which contains a header which determines if the subsequent data is little- or big-endian. I'll probably copy-and-paste @Enet4's implementation, but it would be nice to have here 😇 |
+1 to this. I'm handling old mainframe datasets, and there's a bit that says whether the structures are big-endian or little-endian. This is what I have: struct WrapOrder<O: ByteOrder> {
marker: std::marker::PhantomData<O>,
}
trait WrappedOrder {
fn read_u16(&self, buf: &[u8]) -> u16;
fn read_u32(&self, buf: &[u8]) -> u32;
}
impl<O: ByteOrder> WrappedOrder for WrapOrder<O> {
fn read_u16(&self, buf: &[u8]) -> u16 { O::read_u16(buf) }
fn read_u32(&self, buf: &[u8]) -> u32 { O::read_u32(buf) }
} |
I did some research on the crates available for this, and none of them seems to cover this use case particularly well. What do you folks think of creating a new crate to cover this run-time endianness artifact? Later on, upon an appropriate agreement, it could be re-exported here. |
I just ran into a real-world case when this is useful: tiff file format. It has marker at the beginning telling reader whether it's big endian or little endian. Every single value in the file is then ordered accordingly. |
Another use case: I want to make a "generic" Diesel backend (so I can swap it between a real and test one), but the Backend trait includes ByteOrder, so I can't make this without limiting it to only one byte ordering. If it wasn't for the Sealed trait I'd just build my own... |
Could we help to solve this issue? Is anything planned or in progress? |
@yageek I believe one of the main concerns here is that there is no general consensus on how the API should work here. A run-time Endianness API such as the one I proposed above would not be fully compatible with some parts of the API shown here (e.g. |
@Enet4 I’m glad you’re working on it. I saw that the nightly includes some primitives dealing with endianness too. Make it sense to base current work on those instead of using this crate ? |
Which things did you see in nightly? |
I think I saw some |
Those are stable methods. |
Yeah byteorder already uses those. I'm not aware of anything stable or about to be stable that has any significance to this particular issue. |
I mixed up with the |
|
A tiny update, I pushed Renamed the concept crate to |
The X11 protocol also has byte order that is selectable at runtime. |
From a discussion on
#rust-beginners
there seems to be a need forByteOrder
implementation that dispatches to LE/BE based on runtime information.Essentially something like this:
The
byteorder
docs don't seem to say that the crate is focused solely on static/type-level checking, so I'm guessing this would be in scope for the library.Of course this isn't strictly necessary, as you can probably just write reading/writing code generically and simply move the
LE
/BE
decision to a higher level, but it may simplify some use cases regardless.The text was updated successfully, but these errors were encountered: