Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow for no-std build (extracts std feature, on by default) #13

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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