Been playing around with PhantomData in rust. Example usage in Rust's documentation deals with unsafe code and referemces, but what follows is an example in deserialization that doesn't touch unsafe code at all.

Say I wanted to implement something like `TryFrom<&[u8]>` for u16. There's an issue here: is the u16 in little endian or in big endian order? The obvious (but dirty) answer is to pick an endian and swap when necessary.

What about newtype wrappers? I could create `LEu16` and `BEu16` and implement for these separately. However, this is mildly annoying.

However, what if we tied some extra data to a single wrapper? e.g. you deserialized a Wrappedu16<BigEndian>.

Of course Rust doesn't like unused template parameters, so PhantomData comes to the rescue:

struct Wrappedu16<Endian>(u16, PhantomData<Endian>)


and then I could implement TryFrom roughly like thus using the byteorder crate:

impl<'a, Endian> TryFrom<&'a [u8]> for Wrappedu16<Endian>
where Endian: byteorder::ByteOrder {
fn try_from(src: &'a [u8]) -> Result<Self, !> {
Ok(Endian::read_u16(src)) // panics, unfortunately

It's not perfect by any means, but I think it's pretty neat!

Note: this is an example based on, but not equal to the case I actually developed it for. The focus is the technique, not the specific trait implemented.

Also: I like markdown, it's a shame that it doesn't actually work here.

Why'd I decide to type this all out on my phone? >_>

Sign in to participate in the conversation
Mastodon for Tech Folks

This Mastodon instance is for people interested in technology. Discussions aren't limited to technology, because tech folks shouldn't be limited to technology either!