pub trait Flip: Sized {
    fn flip_val_swapped(&self) -> Self;

    fn flip_val(&self, endian: Endian) -> Self { ... }
    fn flip_var_swapped(&mut self) { ... }
    fn flip_var(&mut self, endian: Endian) { ... }
}
Expand description

Defines types whose values can be endian-flipped.

Note: In this crate, the term encast means decoding a number of bytes to one or more values, the term decast means encoding one or more variables to a number of bytes, and the term endian-flip means flipping the endianness of value(s).

Description

A type is Flip if

  • it is a numeric type, i.e.,
    • i8, i16, i32, i64, i128, isize,
    • u8, u16, u32, u64, u128, usize,
    • f32, or f64,
  • it is an array type whose element is Flip, or
  • it is a struct type whose all members are Flip and implements Flip by declaring #[derive(Flip)].

As you may have noticed, the types that trait Flip can be implemented for is similar to the types that trait Cast can be implemented for. The difference is that trait Flip cannot be implemented for a union type by declaring #[derive(Flip)], while trait Cast can be implemented for a union type by declaring #[derive(Cast)]. Because there is no automatic way to flip the endianness of a union type, #[derive(Flip)] does not support a union type. This is the reason why trait Flip is defined independently from trait Cast.

FYI: There would be a need to flip the endianness of a struct type containing a union type. In such a case, those members whose types are not union types should be automatically endian-flipped, while those members whose types are union types must be manually endian-flipped. In such a situation, #[derive([NopFlip)] would be a help. It nominally implements trait Flip whose methods do nothing (Nop = No operation). See the description of trait NopFlip for more information.

Also note that trait Flip is not a subtrait of trait Copy.

Example 1

In the example below, #[derive(Flip)] makes the value of UdpHdr endian-flippable so that method encastf and method decastf can flip the endianness of their results.

use castflip::{Cast, Flip, EncastMem, DecastMem, BE};

#[repr(C)]
#[derive(Cast, Flip)]
struct UdpHdr {     // UDP: https://www.rfc-editor.org/rfc/rfc768.txt
    sport:  u16,    // UDP Source Port
    dport:  u16,    // UDP Destination Port
    len:    u16,    // UDP Length
    sum:    u16,    // UDP Checksum
}

// Input data: UDP header (8 bytes)
let bytes1: [u8; 8] = [0xC3, 0xC9, 0x00, 0x35, 0x00, 0x32, 0x82, 0x3F];

// Decode bytes `bytes1` to variable `udp_hdr2`.
let udp_hdr2: UdpHdr = bytes1.encastf(BE)?;  // BE = Big-Endian

// Encode the resulting UDP header `udp_hdr2` to bytes `bytes3`.
let mut bytes3 = [0_u8; 8];
let size3 = bytes3.decastf(&udp_hdr2, BE)?;

// Check the results (udp_hdr2)
assert_eq!(udp_hdr2.sport, 0xC3C9); // = 50121
assert_eq!(udp_hdr2.dport, 0x0035); // = 53 (DNS)
assert_eq!(udp_hdr2.len,   0x0032); // = 50
assert_eq!(udp_hdr2.sum,   0x823F);

// Check the results (bytes3)
assert_eq!(size3, 8);
assert_eq!(bytes3, bytes1);

In the example above, method encastf decodes bytes in bytes1 in big-endian (BE) to variable udp_hdr2 of type UdpHdr. Then, method decastf encodes the resulting value in udp_hdr2 to bytes in big-endian (BE) and stores them in bytes3.

Note: UDP is one of the fundamental protocols in the internet protocol suite.

Example 2

In typical cases, the methods defined in trait Flip are called automatically inside this crate. However, they may need to be called manually in certain situations, e.g. to flip the endianness of union types. As the example below shows, trait Flip has two types of methods: flip_val and flip_var.

use castflip::{Flip, LE, BE};

// Get the endian-flipped value of `val1`.
let val1 = 0x1234_u16;
let val2 = val1.flip_val(LE);  // LE = Little-Endian

// Get the endian-flipped value of an integer.
let val3 = 0x5678_u16.flip_val(BE);  // BE = Big-Endian

// Flip the endianness of variable `var4`.
let mut var4 = 0xABCD_u16;
var4.flip_var(LE);  // LE = Little-Endian

if cfg!(target_endian = "little") {
    assert_eq!(val2, 0x1234);
    assert_eq!(val3, 0x7856);  // Swapped
    assert_eq!(var4, 0xABCD);
} else if cfg!(target_endian = "big") {
    assert_eq!(val2, 0x3412);  // Swapped
    assert_eq!(val3, 0x5678);
    assert_eq!(var4, 0xCDAB);  // Swapped
}

In the example above, method flip_val returns a value. If the specified endian is the same as the endianness of the target system, it returns exactly the same value as self. Otherwise, it returns the endian-flipped value of self. In contrast, method flip_var flips the endianness of variable self if the specified endian is different from the endianness of the target system. Note that LE is an alias of Endian::Little, which means Little-Endian. And BE is an alias of Endian::Big, which means Big-Endian.

Required Methods

Returns the endian-flipped value of self.

Provided Methods

Returns the endian-flipped value of self if endian is different from the endianness of the target system. Otherwise, returns exactly the same value as self.

Flips the endianness of the variable (self).

Flips the endianness of the variable (self) if endian is different from the endianness of the target system.

Implementations on Foreign Types

Implementors