Skip to content

Commit

Permalink
Add "inline" feature (fixes #1)
Browse files Browse the repository at this point in the history
  • Loading branch information
alexforster committed Jun 13, 2020
1 parent 48ce872 commit adf428b
Show file tree
Hide file tree
Showing 10 changed files with 109 additions and 0 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ maintenance = { status = "passively-maintained" }
[features]
default = ["std"]
std = []
inline = []

[dev-dependencies]
base16 = { version = "~0.2" }
Expand Down
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@ In addition, unrecognized upper protocols are accessible as bytes via `Raw` enum
pdu = "1.0"
```

The following features are available on this crate:

* `std` (default: *enabled*) – implement `std::error::Error` and `std::fmt::Display` on this crate's `Error` enum
* `inline` (default: *disabled*) – apply the `#[inline(always)]` attribute to all functions in this crate

#### Examples

```rust
Expand Down
12 changes: 12 additions & 0 deletions src/arp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ pub struct ArpPdu<'a> {

impl<'a> ArpPdu<'a> {
/// Constructs an [`ArpPdu`] backed by the provided `buffer`
#[cfg_attr(feature = "inline", inline(always))]
pub fn new(buffer: &'a [u8]) -> Result<Self> {
if buffer.len() < 12 {
return Err(Error::Truncated);
Expand All @@ -48,53 +49,64 @@ impl<'a> ArpPdu<'a> {
}

/// Returns a reference to the entire underlying buffer that was provided during construction
#[cfg_attr(feature = "inline", inline(always))]
pub fn buffer(&'a self) -> &'a [u8] {
self.buffer
}

/// Returns the slice of the underlying buffer that contains this PDU
#[cfg_attr(feature = "inline", inline(always))]
pub fn as_bytes(&'a self) -> &'a [u8] {
&self.buffer[0..28]
}

#[cfg_attr(feature = "inline", inline(always))]
pub fn hardware_type(&'a self) -> u16 {
u16::from_be_bytes(self.buffer[0..=1].try_into().unwrap())
}

#[cfg_attr(feature = "inline", inline(always))]
pub fn protocol_type(&'a self) -> u16 {
u16::from_be_bytes(self.buffer[2..=3].try_into().unwrap())
}

#[cfg_attr(feature = "inline", inline(always))]
pub fn hardware_length(&'a self) -> u8 {
self.buffer[4]
}

#[cfg_attr(feature = "inline", inline(always))]
pub fn protocol_length(&'a self) -> u8 {
self.buffer[5]
}

#[cfg_attr(feature = "inline", inline(always))]
pub fn opcode(&'a self) -> u16 {
u16::from_be_bytes(self.buffer[6..=7].try_into().unwrap())
}

#[cfg_attr(feature = "inline", inline(always))]
pub fn sender_hardware_address(&'a self) -> [u8; 6] {
let mut sender_hardware_address = [0u8; 6];
sender_hardware_address.copy_from_slice(&self.buffer[8..14]);
sender_hardware_address
}

#[cfg_attr(feature = "inline", inline(always))]
pub fn sender_protocol_address(&'a self) -> [u8; 4] {
let mut sender_protocol_address = [0u8; 4];
sender_protocol_address.copy_from_slice(&self.buffer[14..18]);
sender_protocol_address
}

#[cfg_attr(feature = "inline", inline(always))]
pub fn target_hardware_address(&'a self) -> [u8; 6] {
let mut target_hardware_address = [0u8; 6];
target_hardware_address.copy_from_slice(&self.buffer[18..24]);
target_hardware_address
}

#[cfg_attr(feature = "inline", inline(always))]
pub fn target_protocol_address(&'a self) -> [u8; 4] {
let mut target_protocol_address = [0u8; 4];
target_protocol_address.copy_from_slice(&self.buffer[24..28]);
Expand Down
12 changes: 12 additions & 0 deletions src/ethernet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ pub enum Ethernet<'a> {

impl<'a> EthernetPdu<'a> {
/// Constructs an [`EthernetPdu`] backed by the provided `buffer`
#[cfg_attr(feature = "inline", inline(always))]
pub fn new(buffer: &'a [u8]) -> Result<Self> {
if buffer.len() < 14 {
return Err(Error::Truncated);
Expand All @@ -63,16 +64,19 @@ impl<'a> EthernetPdu<'a> {
}

/// Returns a reference to the entire underlying buffer that was provided during construction
#[cfg_attr(feature = "inline", inline(always))]
pub fn buffer(&'a self) -> &'a [u8] {
self.buffer
}

/// Returns the slice of the underlying buffer that contains the header part of this PDU
#[cfg_attr(feature = "inline", inline(always))]
pub fn as_bytes(&'a self) -> &'a [u8] {
&self.buffer[0..self.computed_ihl()]
}

/// Returns an object representing the inner payload of this PDU
#[cfg_attr(feature = "inline", inline(always))]
pub fn inner(&'a self) -> Result<Ethernet<'a>> {
let rest = &self.buffer[self.computed_ihl()..];
Ok(match self.ethertype() {
Expand All @@ -83,50 +87,58 @@ impl<'a> EthernetPdu<'a> {
})
}

#[cfg_attr(feature = "inline", inline(always))]
pub fn computed_ihl(&'a self) -> usize {
match self.tpid() {
EtherType::DOT1Q => 18,
_ => 14,
}
}

#[cfg_attr(feature = "inline", inline(always))]
pub fn source_address(&'a self) -> [u8; 6] {
let mut source_address = [0u8; 6];
source_address.copy_from_slice(&self.buffer[6..12]);
source_address
}

#[cfg_attr(feature = "inline", inline(always))]
pub fn destination_address(&'a self) -> [u8; 6] {
let mut destination_address = [0u8; 6];
destination_address.copy_from_slice(&self.buffer[0..6]);
destination_address
}

#[cfg_attr(feature = "inline", inline(always))]
pub fn tpid(&'a self) -> u16 {
u16::from_be_bytes(self.buffer[12..=13].try_into().unwrap())
}

#[cfg_attr(feature = "inline", inline(always))]
pub fn ethertype(&'a self) -> u16 {
match self.tpid() {
EtherType::DOT1Q => u16::from_be_bytes(self.buffer[16..=17].try_into().unwrap()),
ethertype => ethertype,
}
}

#[cfg_attr(feature = "inline", inline(always))]
pub fn vlan(&'a self) -> Option<u16> {
match self.tpid() {
EtherType::DOT1Q => Some(u16::from_be_bytes(self.buffer[14..=15].try_into().unwrap()) & 0x0FFF),
_ => None,
}
}

#[cfg_attr(feature = "inline", inline(always))]
pub fn vlan_pcp(&'a self) -> Option<u8> {
match self.tpid() {
EtherType::DOT1Q => Some((self.buffer[14] & 0xE0) >> 5),
_ => None,
}
}

#[cfg_attr(feature = "inline", inline(always))]
pub fn vlan_dei(&'a self) -> Option<bool> {
match self.tpid() {
EtherType::DOT1Q => Some(((self.buffer[14] & 0x10) >> 4) > 0),
Expand Down
14 changes: 14 additions & 0 deletions src/gre.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ pub enum Gre<'a> {

impl<'a> GrePdu<'a> {
/// Constructs a [`GrePdu`] backed by the provided `buffer`
#[cfg_attr(feature = "inline", inline(always))]
pub fn new(buffer: &'a [u8]) -> Result<Self> {
if buffer.len() < 4 {
return Err(Error::Truncated);
Expand All @@ -53,16 +54,19 @@ impl<'a> GrePdu<'a> {
}

/// Returns a reference to the entire underlying buffer that was provided during construction
#[cfg_attr(feature = "inline", inline(always))]
pub fn buffer(&'a self) -> &'a [u8] {
self.buffer
}

/// Returns the slice of the underlying buffer that contains the header part of this PDU
#[cfg_attr(feature = "inline", inline(always))]
pub fn as_bytes(&'a self) -> &'a [u8] {
&self.buffer[0..self.computed_ihl()]
}

/// Returns an object representing the inner payload of this PDU
#[cfg_attr(feature = "inline", inline(always))]
pub fn inner(&'a self) -> Result<Gre<'a>> {
let rest = &self.buffer[self.computed_ihl()..];
Ok(match self.ethertype() {
Expand All @@ -73,6 +77,7 @@ impl<'a> GrePdu<'a> {
})
}

#[cfg_attr(feature = "inline", inline(always))]
pub fn computed_ihl(&'a self) -> usize {
let mut ihl = 4;
if self.has_checksum() {
Expand All @@ -87,26 +92,32 @@ impl<'a> GrePdu<'a> {
ihl
}

#[cfg_attr(feature = "inline", inline(always))]
pub fn version(&'a self) -> u8 {
self.buffer[1] & 0x07
}

#[cfg_attr(feature = "inline", inline(always))]
pub fn ethertype(&'a self) -> u16 {
u16::from_be_bytes(self.buffer[2..=3].try_into().unwrap())
}

#[cfg_attr(feature = "inline", inline(always))]
pub fn has_checksum(&'a self) -> bool {
(self.buffer[0] & 0x80) != 0
}

#[cfg_attr(feature = "inline", inline(always))]
pub fn has_key(&'a self) -> bool {
(self.buffer[0] & 0x20) != 0
}

#[cfg_attr(feature = "inline", inline(always))]
pub fn has_sequence_number(&'a self) -> bool {
(self.buffer[0] & 0x10) != 0
}

#[cfg_attr(feature = "inline", inline(always))]
pub fn checksum(&'a self) -> Option<u16> {
if self.has_checksum() {
Some(u16::from_be_bytes(self.buffer[4..=5].try_into().unwrap()))
Expand All @@ -115,6 +126,7 @@ impl<'a> GrePdu<'a> {
}
}

#[cfg_attr(feature = "inline", inline(always))]
pub fn computed_checksum(&'a self) -> Option<u16> {
if self.has_checksum() {
Some(util::checksum(&[&self.buffer[0..=3], &self.buffer[6..]]))
Expand All @@ -123,6 +135,7 @@ impl<'a> GrePdu<'a> {
}
}

#[cfg_attr(feature = "inline", inline(always))]
pub fn key(&'a self) -> Option<u32> {
if self.has_checksum() && self.has_key() {
Some(u32::from_be_bytes(self.buffer[8..=11].try_into().unwrap()))
Expand All @@ -133,6 +146,7 @@ impl<'a> GrePdu<'a> {
}
}

#[cfg_attr(feature = "inline", inline(always))]
pub fn sequence_number(&'a self) -> Option<u32> {
if self.has_sequence_number() && self.has_checksum() && self.has_key() {
Some(u32::from_be_bytes(self.buffer[12..=15].try_into().unwrap()))
Expand Down
8 changes: 8 additions & 0 deletions src/icmp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ pub struct IcmpPdu<'a> {

impl<'a> IcmpPdu<'a> {
/// Constructs a [`IcmpPdu`] backed by the provided `buffer`
#[cfg_attr(feature = "inline", inline(always))]
pub fn new(buffer: &'a [u8]) -> Result<Self> {
if buffer.len() < 8 {
return Err(Error::Truncated);
Expand All @@ -36,27 +37,33 @@ impl<'a> IcmpPdu<'a> {
}

/// Returns a reference to the entire underlying buffer that was provided during construction
#[cfg_attr(feature = "inline", inline(always))]
pub fn buffer(&'a self) -> &'a [u8] {
self.buffer
}

/// Returns the slice of the underlying buffer that contains this PDU
#[cfg_attr(feature = "inline", inline(always))]
pub fn as_bytes(&'a self) -> &'a [u8] {
&self.buffer[0..8]
}

#[cfg_attr(feature = "inline", inline(always))]
pub fn message_type(&'a self) -> u8 {
self.buffer[0]
}

#[cfg_attr(feature = "inline", inline(always))]
pub fn message_code(&'a self) -> u8 {
self.buffer[1]
}

#[cfg_attr(feature = "inline", inline(always))]
pub fn checksum(&'a self) -> u16 {
u16::from_be_bytes(self.buffer[2..=3].try_into().unwrap())
}

#[cfg_attr(feature = "inline", inline(always))]
pub fn computed_checksum(&'a self, ip: &crate::Ip) -> u16 {
match ip {
crate::Ip::Ipv4(_) => util::checksum(&[&self.buffer[0..=1], &self.buffer[4..]]),
Expand All @@ -71,6 +78,7 @@ impl<'a> IcmpPdu<'a> {
}
}

#[cfg_attr(feature = "inline", inline(always))]
pub fn message(&'a self) -> &'a [u8] {
&self.buffer[4..]
}
Expand Down
Loading

0 comments on commit adf428b

Please sign in to comment.