Skip to content

Commit

Permalink
Allow for no-std build (extracts std feature, on by default)
Browse files Browse the repository at this point in the history
  • Loading branch information
kevinclark committed Aug 19, 2024
1 parent cad9f4a commit cc8685c
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 43 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# ChangeLog

## Unreleased
- Extracted RtpPacketBuilder::build and Errors to 'std' feature, which is on by default.

### Changed
- Switched to Rust 2021 edition.
Expand Down
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,7 @@ criterion = "0.5"
[[bench]]
name = "bench"
harness = false

[features]
default = ["std"]
std = []
42 changes: 24 additions & 18 deletions src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,7 @@ impl<'a> RtpPacketBuilder<'a> {

/// Build the RTP packet.
/// On success, it returns a buffer containing the target packet.
#[cfg(feature = "std")]
pub fn build(&self) -> Result<Vec<u8>, RtpPacketBuildError> {
self.validate_content()?;

Expand All @@ -324,7 +325,7 @@ impl<'a> RtpPacketBuilder<'a> {

Ok(buffer)
}

fn validate_content(&self) -> Result<(), RtpPacketBuildError> {
if (self.payload_type & (!0x7F)) != 0 {
return Err(RtpPacketBuildError::PayloadTypeInvalid);
Expand All @@ -344,10 +345,12 @@ impl<'a> RtpPacketBuilder<'a> {
}
}

// When Rust 1.81 drops with Error in core, this feature gate can be removed.
#[cfg(feature = "std")]
impl std::error::Error for RtpPacketBuildError {}

impl std::fmt::Display for RtpPacketBuildError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
impl core::fmt::Display for RtpPacketBuildError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(
f,
"{}",
Expand All @@ -367,54 +370,57 @@ mod test {

#[test]
fn test_padded() {
let payload = vec![1u8];
let packet = RtpPacketBuilder::new()
let payload = [1u8];
let mut buffer = [0u8; 16];
RtpPacketBuilder::new()
.payload_type(1)
.payload(&payload)
.padded(Pad::round_to(4))
.build()
.build_into(&mut buffer)
.unwrap();

assert_eq!(packet.len() & 0x03, 0);
assert!(crate::reader::RtpReader::new(&packet)
assert_eq!(buffer[0] & 0x03, 0);
assert!(crate::reader::RtpReader::new(&buffer)
.unwrap()
.padding()
.is_some());
}

#[test]
fn test_padding_not_needed() {
let payload = vec![1u8; 4];
let packet = RtpPacketBuilder::new()
let mut buffer = [0u8; 16];
let payload = [1u8; 4];
let packet_len = RtpPacketBuilder::new()
.payload_type(1)
.payload(&payload)
.padded(Pad::round_to(4))
.build()
.build_into(&mut buffer)
.unwrap();

// assert the length is not increased beyond the 12 bytes of header + the payload
assert_eq!(packet.len(), 12 + payload.len());
assert!(crate::reader::RtpReader::new(&packet)
assert_eq!(packet_len, 12 + payload.len());
assert!(crate::reader::RtpReader::new(&buffer[..packet_len])
.unwrap()
.padding()
.is_none());
}

#[test]
fn test_not_padded() {
let payload = vec![1u8];
let packet = RtpPacketBuilder::new()
let mut buffer = [0u8; 16];
let payload = [1u8];
let packet_len = RtpPacketBuilder::new()
.payload_type(1)
.payload(&payload)
.build()
.build_into(&mut buffer)
.unwrap();

assert_eq!(packet.len() & 0x03, 1);
assert_eq!(packet_len & 0x03, 1);
}

#[test]
fn test_would_run() {
let extension = vec![1u8, 2, 3, 4];
let extension = [1u8, 2, 3, 4];
let builder = RtpPacketBuilder::new()
.payload_type(12)
.extension(1, &extension);
Expand Down
51 changes: 38 additions & 13 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@
//! ```
//! use rtp_rs::*;
//!
//! let payload = vec![0u8, 2, 5, 4, 6];
//! let mut buffer = [0u8; 1024];
//! let payload = [0u8, 2, 5, 4, 6];
//! let result = RtpPacketBuilder::new()
//! .payload_type(111)
//! .ssrc(1337)
Expand All @@ -28,15 +29,39 @@
//! .padded(Pad::round_to(4))
//! .marked(true)
//! .payload(&payload)
//! .build();
//! if let Ok(packet) = result {
//! println!("Packet: {:?}", packet);
//! .build_into(&mut buffer);
//!
//! if let Ok(len) = result {
//! println!("Packet: {:?}", &buffer[..len]);
//! }
//! ```
#![cfg_attr(feature = "std", doc = r#"
Building a packet with std enabled lets you skip the buffer;
```
use rtp_rs::*;
let payload = vec![0u8, 2, 5, 4, 6];
let result = RtpPacketBuilder::new()
.payload_type(111)
.ssrc(1337)
.sequence(Seq::from(1234))
.timestamp(666657)
.padded(Pad::round_to(4))
.marked(true)
.payload(&payload)
.build();
if let Ok(packet) = result {
println!("Packet: {:?}", packet);
}
```"#)]

#![forbid(unsafe_code)]
#![deny(rust_2018_idioms, future_incompatible, missing_docs)]

#![cfg_attr(not(feature = "std"), no_std)]

/// 16 bit RTP sequence number value, as obtained from the `sequence_number()` method of RtpReader.
///
/// ```
Expand Down Expand Up @@ -104,32 +129,32 @@ impl From<u16> for Seq {
/// `1` (rather than `-65535`).
///
/// This is for symmetry with addition, where for example `Seq(0xffff) + 1` gives `Seq(0x0000)`
impl std::ops::Sub for Seq {
impl core::ops::Sub for Seq {
type Output = i32;

fn sub(self, rhs: Seq) -> Self::Output {
let delta = i32::from(self.0) - i32::from(rhs.0);
if delta < std::i16::MIN as i32 {
std::u16::MAX as i32 + 1 + delta
} else if delta > std::i16::MAX as i32 {
delta - std::u16::MAX as i32 - 1
if delta < core::i16::MIN as i32 {
core::u16::MAX as i32 + 1 + delta
} else if delta > core::i16::MAX as i32 {
delta - core::u16::MAX as i32 - 1
} else {
delta
}
}
}
impl PartialOrd for Seq {
fn partial_cmp(&self, other: &Seq) -> Option<std::cmp::Ordering> {
fn partial_cmp(&self, other: &Seq) -> Option<core::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Seq {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
(*self - *other).cmp(&0)
}
}

impl std::ops::Add<u16> for Seq {
impl core::ops::Add<u16> for Seq {
type Output = Seq;

fn add(self, rhs: u16) -> Self::Output {
Expand All @@ -142,7 +167,7 @@ pub trait IntoSeqIterator {
/// Produce an `Iterator` over sequence number values
fn seq_iter(self) -> SeqIter;
}
impl IntoSeqIterator for std::ops::Range<Seq> {
impl IntoSeqIterator for core::ops::Range<Seq> {
fn seq_iter(self) -> SeqIter {
SeqIter(self.start, self.end)
}
Expand Down
44 changes: 32 additions & 12 deletions src/reader.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::{RtpPacketBuilder, Seq};
use std::fmt;
use core::fmt;

/// Wrapper around a byte-slice of RTP data, providing accessor methods for the RTP header fields.
pub struct RtpReader<'a> {
Expand Down Expand Up @@ -281,10 +281,13 @@ impl<'a> fmt::Debug for RtpReader<'a> {
}
}

// When Rust 1.81 drops with Error in core, this feature gate can be removed.
#[cfg(feature = "std")]
impl std::error::Error for RtpReaderError {}

impl std::fmt::Display for RtpReaderError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
impl core::fmt::Display for RtpReaderError {
#[cfg(feature = "std")]
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(
f,
"{}",
Expand All @@ -301,6 +304,20 @@ impl std::fmt::Display for RtpReaderError {
}
)
}

#[cfg(not(feature = "std"))]
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(
f,
"{}",
match self {
RtpReaderError::BufferTooShort(_) => "buffer too short",
RtpReaderError::UnsupportedVersion(_) => "unsupported version",
RtpReaderError::HeadersTruncated { header_len: _, buffer_len: _ } => "headers truncated",
RtpReaderError::PaddingLengthInvalid(_) => "padding length invalid",
}
)
}
}

#[cfg(test)]
Expand Down Expand Up @@ -368,7 +385,7 @@ mod tests {
assert_eq!(1_692_665_255, reader.timestamp());
assert_eq!(0xa242_af01, reader.ssrc());
assert_eq!(379, reader.payload().len());
format!("{:?}", reader);
format_args!("{:?}", reader);
}

#[test]
Expand All @@ -395,30 +412,33 @@ mod tests {
#[test]
fn builder_juggle() {
let reader = RtpReader::new(&TEST_RTP_PACKET).unwrap();
let buffer = reader.create_builder().build().unwrap();
let mut buffer = [0u8; 1024];
let buf_len = reader.create_builder().build_into(&mut buffer).unwrap();

assert_eq!(buffer.as_slice(), &TEST_RTP_PACKET[..]);
assert_eq!(&buffer[..buf_len], &TEST_RTP_PACKET[..]);
}

#[test]
fn builder_juggle_extension() {
let reader = RtpReader::new(&TEST_RTP_PACKET_WITH_EXTENSION).unwrap();
let buffer = reader.create_builder().build().unwrap();
assert_eq!(buffer.as_slice(), &TEST_RTP_PACKET_WITH_EXTENSION[..]);
let mut buffer = [0u8; 1024];
let buf_len = reader.create_builder().build_into(&mut buffer).unwrap();
assert_eq!(&buffer[..buf_len], &TEST_RTP_PACKET_WITH_EXTENSION[..]);
}

#[test]
fn builder_juggle_clear_payload() {
let new_payload = vec![];
let new_payload = [0u8; 0];
let reader = RtpReader::new(&TEST_RTP_PACKET_WITH_EXTENSION).unwrap();
let buffer = reader
let mut buffer = [0u8; 1024];
let buf_len = reader
.create_builder()
.payload(&new_payload)
.build()
.build_into(&mut buffer)
.unwrap();

let expected = &TEST_RTP_PACKET_WITH_EXTENSION[0..(3 + 4) * 4];
assert_eq!(buffer.as_slice(), expected);
assert_eq!(&buffer[..buf_len], expected);
}

#[test]
Expand Down

0 comments on commit cc8685c

Please sign in to comment.