pub trait EncastIO {
fn encast<T>(&mut self) -> Result<T>
where
T: Cast;
fn encastf<T>(&mut self, endian: Endian) -> Result<T>
where
T: Cast + Flip;
fn encasts<T>(&mut self, slice: &mut [T]) -> Result<usize>
where
T: Cast;
fn encastsf<T>(&mut self, slice: &mut [T], endian: Endian) -> Result<usize>
where
T: Cast + Flip;
fn encastv<T>(&mut self, nelem: usize) -> Result<Vec<T>>
where
T: Cast;
fn encastvf<T>(&mut self, nelem: usize, endian: Endian) -> Result<Vec<T>>
where
T: Cast + Flip;
}
Expand description
Defines methods to encast
and endian-flip
through io::Read
.
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).
Example 1
In the example below, method encastf
decodes bytes from input1
in Big-Endian (BE
) to variable udp_hdr2
of type UdpHdr
.
Note that io::Cursor
wraps an in-memory buffer and provides it
through io::Read
.
use std::io::Cursor;
use castflip::{Cast, Flip, EncastIO, 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) + part of DNS header (8 bytes)
let bytes1: [u8; 16] = [0xC3, 0xC9, 0x00, 0x35, 0x00, 0x32, 0x82, 0x3F,
0x1A, 0xD1, 0x01, 0x20, 0x00, 0x01, 0x00, 0x00];
let mut input1 = Cursor::new(bytes1);
// Decode input `input1` to variable `udp_hdr2`.
// Because the UDP header is 8 bytes as defined above, only
// the first 8 bytes are decoded, remaining 8 bytes are ignored.
let udp_hdr2: UdpHdr = input1.encastf(BE)?; // BE = Big-Endian
// 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);
Description
All methods in trait EncastIO
encast
a number of bytes read
from I/O to one or more values of the specified type. The type of
the value(s) can be explicitly specified as the generic type
parameter of the methods or implicitly specified so that the Rust
compiler can infer it. The methods whose name contain ‘s’ (=
slice) or ‘v’ (= vector) encast
a series of structured binary
data. The methods whose names end with ‘f’ flip the endianness of
the results. Currently, an implementation for trait io::Read
is provided.
The input self
should have enough bytes to decode to the
specified number of value(s) of the specified type T
. If there
are enough bytes, the required number of bytes are read from I/O
and decoded to the specified type of value(s). The remaining
bytes in input self
are untouched. If successful, return value
is enclosed in Ok
(). If failed, Err
(io::Error
) is
returned. The type of the return value is io::Result
.
When argument endian
is specified, the endianness of value(s) is
flipped if necessary.
Example 2
Because io::Read
is implemented for &[u8]
, EncastIO
can
encast
from memory. The example below is almost the same with
Example 1 except it uses a mutable slice instead of io::Cursor
.
use castflip::{Cast, Flip, EncastIO, 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) + part of DNS header (8 bytes)
let bytes1: [u8; 16] = [0xC3, 0xC9, 0x00, 0x35, 0x00, 0x32, 0x82, 0x3F,
0x1A, 0xD1, 0x01, 0x20, 0x00, 0x01, 0x00, 0x00];
let mut slice1 = &bytes1[..];
// Decode slice `slice1` to variable `udp_hdr2`.
// Because the UDP header is 8 bytes as defined above, only
// the first 8 bytes are decoded, remaining 8 bytes are ignored.
let udp_hdr2: UdpHdr = slice1.encastf(BE)?; // BE = Big-Endian
// 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 result (slice1)
// Note: `slice1` contains unread part.
assert_eq!(slice1.len(), 8);
assert_eq!(slice1, &bytes1[8..16]);
Required Methods
Decodes the bytes read from input self
to a value of type
T
and returns the value. The endianness of the resulting
value is not flipped.
Decodes the bytes read from input self
to a value of type
T
and returns the value. The endianness of the resulting
value is flipped if necessary. The endianness of the bytes is
specified in endian
.
Decodes the bytes read from input self
to value(s) of type
T
and fill slice
with the value(s). It returns the number
of decoded bytes. The endianness of the resulting value(s) is
not flipped.
Decodes the bytes read from input self
to value(s) of type
T
and fill slice
with the value(s). It returns the number
of decoded bytes. The endianness of the resulting value(s) is
flipped if necessary. The endianness of the bytes is
specified in endian
.
Decodes the bytes read from input self
to a vector of
value(s) of type T
and returns the vector. The endianness
of the resulting value(s) is not flipped. The number of
elements in the resulting vecotr is specified in nelem
.
Decodes the bytes read from input self
to a vector of
value(s) of type T
and returns the vector. The endianness
of the resulting value(s) is flipped if necessary. The
endianness of the bytes is specified in endian
. The number
of elements in the resulting vecotr is specified in nelem
.