Skip to content

Commit 9d99f9f

Browse files
authored
Use identity ToStatic impls for the Copy identity types (algesten#975)
The derive generates a separate shadow Static type that isn't Eq/Hash/Borrow<Self>, so a derived identity type can't be a HashMap key inside a #[drv::memo] projection. These types are all Copy with a structural PartialEq, so an identity ToStatic (Static = Self) is the correct shape — it works as both a value and a map key, mirroring how drv handles primitives. A small gated drv_identity_copy! macro replaces the per-type derive across Mid/Rid/Ssrc/Pt/SessionId/SeqNo, Direction, MediaKind, VideoOrientation, Codec, the H265 profile types, Frequency, CodecSpec, FormatParams, and MediaTime (folding in its former hand-written impl).
1 parent ee8a2bc commit 9d99f9f

10 files changed

Lines changed: 63 additions & 31 deletions

File tree

src/format/codec.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ use super::format_params::FormatParams;
88

99
/// Codec specification
1010
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
11-
#[cfg_attr(feature = "drv", derive(drv::Input))]
1211
pub struct CodecSpec {
1312
/// The codec identifier.
1413
pub codec: Codec,
@@ -26,7 +25,6 @@ pub struct CodecSpec {
2625

2726
/// Known codecs.
2827
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
29-
#[cfg_attr(feature = "drv", derive(drv::Input))]
3028
#[non_exhaustive]
3129
#[allow(missing_docs)]
3230
pub enum Codec {
@@ -53,6 +51,9 @@ pub enum Codec {
5351
Unknown,
5452
}
5553

54+
#[cfg(feature = "drv")]
55+
crate::drv_identity_copy!(Codec, CodecSpec);
56+
5657
impl Codec {
5758
/// Tells if codec is audio.
5859
pub fn is_audio(&self) -> bool {

src/format/format_params.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ use crate::sdp::FormatParam;
55

66
/// Codec specific format parameters.
77
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default, Serialize, Deserialize)]
8-
#[cfg_attr(feature = "drv", derive(drv::Input))]
98
pub struct FormatParams {
109
/// Opus specific parameter.
1110
///
@@ -101,6 +100,9 @@ pub struct FormatParams {
101100
pub sprop_max_don_diff: Option<u16>,
102101
}
103102

103+
#[cfg(feature = "drv")]
104+
crate::drv_identity_copy!(FormatParams);
105+
104106
impl FormatParams {
105107
/// Parse an fmtp line to create a FormatParams.
106108
///

src/lib.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -687,6 +687,27 @@ use streams::RtpPacket;
687687
use streams::StreamPaused;
688688
use util::InstantExt;
689689

690+
// Identity `drv::ToStatic` (`Static = Self`) for the `Copy` identity types.
691+
// Used instead of `#[derive(drv::Input)]` because the derive's generated
692+
// shadow type isn't `Eq`/`Hash`/`Borrow<Self>`, so it can't be a `HashMap`
693+
// key inside a `#[drv::memo]` projection; `Static = Self` can. `eq_static`
694+
// defers to each type's own `PartialEq`. Each module invokes this for its
695+
// own types.
696+
#[cfg(feature = "drv")]
697+
macro_rules! drv_identity_copy {
698+
($($t:ty),* $(,)?) => {
699+
$(
700+
impl drv::ToStatic for $t {
701+
type Static = $t;
702+
fn to_static(&self) -> $t { *self }
703+
fn eq_static(&self, other: &$t) -> bool { self == other }
704+
}
705+
)*
706+
};
707+
}
708+
#[cfg(feature = "drv")]
709+
pub(crate) use drv_identity_copy;
710+
690711
/// Cryptographic provider traits and implementations.
691712
///
692713
/// This module provides the traits for pluggable cryptographic operations

src/packet/h265_profile.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ use serde::{Deserialize, Serialize};
77
/// Represents the three SDP fmtp parameters `profile-id`, `tier-flag`, and `level-id`
88
/// as defined in RFC 7798 §7.1 and ITU-T H.265 Annex A.
99
#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)]
10-
#[cfg_attr(feature = "drv", derive(drv::Input))]
1110
pub struct H265ProfileTierLevel {
1211
profile: H265Profile,
1312
tier: H265Tier,
@@ -95,7 +94,6 @@ impl From<(u8, u8, u8)> for H265ProfileTierLevel {
9594

9695
/// H.265 profile as defined in ITU-T H.265 Annex A.
9796
#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)]
98-
#[cfg_attr(feature = "drv", derive(drv::Input))]
9997
pub enum H265Profile {
10098
/// Main profile (profile_id=1).
10199
Main,
@@ -162,7 +160,6 @@ impl H265Profile {
162160

163161
/// H.265 tier (Main or High).
164162
#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)]
165-
#[cfg_attr(feature = "drv", derive(drv::Input))]
166163
pub enum H265Tier {
167164
/// Main tier (tier_flag=0).
168165
Main,
@@ -195,7 +192,6 @@ impl H265Tier {
195192
///
196193
/// Level IDs are 30× the level number (e.g., Level 3.1 = 93).
197194
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
198-
#[cfg_attr(feature = "drv", derive(drv::Input))]
199195
#[repr(u8)]
200196
#[rustfmt::skip]
201197
pub enum H265Level {
@@ -227,6 +223,9 @@ pub enum H265Level {
227223
Level6_2 = 186_u8,
228224
}
229225

226+
#[cfg(feature = "drv")]
227+
crate::drv_identity_copy!(H265ProfileTierLevel, H265Profile, H265Tier, H265Level);
228+
230229
impl H265Level {
231230
/// Returns the ordinal position (0-12) representing capability order.
232231
pub fn ordinal(self) -> usize {

src/packet/mod.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,6 @@ mod payload;
6767
pub(crate) use payload::Payloader;
6868

6969
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
70-
#[cfg_attr(feature = "drv", derive(drv::Input))]
7170
/// Types of media.
7271
pub enum MediaKind {
7372
/// Audio media.
@@ -76,6 +75,9 @@ pub enum MediaKind {
7675
Video,
7776
}
7877

78+
#[cfg(feature = "drv")]
79+
crate::drv_identity_copy!(MediaKind);
80+
7981
impl MediaKind {
8082
/// Tests if this is `MediaKind::Audio`
8183
pub fn is_audio(&self) -> bool {

src/rtp/dir.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ use std::fmt;
44
///
55
/// And also extmap direction.
66
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7-
#[cfg_attr(feature = "drv", derive(drv::Input))]
87
pub enum Direction {
98
/// Send only direction.
109
SendOnly,
@@ -16,6 +15,9 @@ pub enum Direction {
1615
Inactive,
1716
}
1817

18+
#[cfg(feature = "drv")]
19+
crate::drv_identity_copy!(Direction);
20+
1921
impl Direction {
2022
/// Change the direction to the opposite.
2123
///

src/rtp/ext.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1222,7 +1222,6 @@ impl fmt::Debug for ExtensionMap {
12221222

12231223
/// How the video is rotated.
12241224
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1225-
#[cfg_attr(feature = "drv", derive(drv::Input))]
12261225
pub enum VideoOrientation {
12271226
/// Not rotated.
12281227
Deg0 = 0,
@@ -1234,6 +1233,9 @@ pub enum VideoOrientation {
12341233
Deg270 = 1,
12351234
}
12361235

1236+
#[cfg(feature = "drv")]
1237+
crate::drv_identity_copy!(VideoOrientation);
1238+
12371239
impl From<u8> for VideoOrientation {
12381240
fn from(value: u8) -> Self {
12391241
match value {

src/rtp/id.rs

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,6 @@ macro_rules! num_id {
123123
/// 3 incoming StreamRx, but since they belong to the same media,
124124
/// the have the same `Mid`.
125125
#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
126-
#[cfg_attr(feature = "drv", derive(drv::Input))]
127126
pub struct Mid([u8; 16]);
128127
str_id!(Mid, "Mid", 16, 3);
129128

@@ -135,7 +134,6 @@ str_id!(Mid, "Mid", 16, 3);
135134
/// In SDP this is an optional value that will be seen in [`MediaData`][crate::media::MediaData]
136135
/// if the remote peer is configured for simulcast.
137136
#[derive(Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
138-
#[cfg_attr(feature = "drv", derive(drv::Input))]
139137
pub struct Rid([u8; 8]);
140138
str_id!(Rid, "Rid", 8, 3);
141139

@@ -145,7 +143,6 @@ str_id!(Rid, "Rid", 8, 3);
145143
/// with at least one synchronization source. Multiple sources for the same stream happens
146144
/// for RTX (resend) and simulcast.
147145
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
148-
#[cfg_attr(feature = "drv", derive(drv::Input))]
149146
pub struct Ssrc(u32);
150147
num_id!(Ssrc, u32);
151148

@@ -166,15 +163,13 @@ impl Ssrc {
166163
///
167164
/// PTs in RTP headers are 7 bits. Values >=128 are not valid.
168165
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
169-
#[cfg_attr(feature = "drv", derive(drv::Input))]
170166
pub struct Pt(u8);
171167
num_id!(Pt, u8);
172168

173169
/// Identifier of an SDP session.
174170
///
175171
/// This value is rarely interesting, but is part of the SDP OFFER and ANSWER.
176172
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
177-
#[cfg_attr(feature = "drv", derive(drv::Input))]
178173
pub struct SessionId(u64);
179174
num_id!(SessionId, u64);
180175

@@ -199,10 +194,12 @@ num_id!(SessionId, u64);
199194
/// assert_eq!(b, 1);
200195
/// ```
201196
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
202-
#[cfg_attr(feature = "drv", derive(drv::Input))]
203197
pub struct SeqNo(u64);
204198
num_id!(SeqNo, u64);
205199

200+
#[cfg(feature = "drv")]
201+
crate::drv_identity_copy!(Mid, Rid, Ssrc, Pt, SessionId, SeqNo);
202+
206203
/// TWCC-specific sequence number.
207204
///
208205
/// Transport-Wide Congestion Control uses its own sequence number space,

src/rtp/mtime.rs

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ use serde::{Deserialize, Serialize};
3333
/// let mtime = MediaTime::new(2000, freq);
3434
/// ```
3535
#[derive(Debug, Clone, Copy, Serialize)]
36-
#[cfg_attr(feature = "drv", derive(drv::Input))]
3736
pub struct Frequency(NonZeroU32);
3837

3938
impl Frequency {
@@ -333,21 +332,8 @@ impl PartialEq for MediaTime {
333332
}
334333
impl Eq for MediaTime {}
335334

336-
// `MediaTime`'s `PartialEq` rebases to a common timebase before comparing,
337-
// so the structural `drv::Input` derive (raw numerator + frequency) would
338-
// diverge from its real equality. It's `Copy + 'static`, so give it an
339-
// identity `ToStatic` that defers to that `PartialEq` — mirroring how drv
340-
// treats primitives.
341335
#[cfg(feature = "drv")]
342-
impl drv::ToStatic for MediaTime {
343-
type Static = MediaTime;
344-
fn to_static(&self) -> MediaTime {
345-
*self
346-
}
347-
fn eq_static(&self, other: &MediaTime) -> bool {
348-
self == other
349-
}
350-
}
336+
crate::drv_identity_copy!(Frequency, MediaTime);
351337

352338
impl PartialOrd for MediaTime {
353339
#[inline(always)]

tests/drv_input.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
//! identity types so downstream `#[drv::memo]` queries can take them by
44
//! value. `Frequency` exercises the `NonZeroU32` path specifically.
55
6+
use std::collections::HashMap;
7+
68
use str0m::format::Codec;
79
use str0m::media::{Frequency, MediaKind, MediaTime, Mid};
810

@@ -60,3 +62,21 @@ fn media_time_is_a_valid_memo_input() {
6062
assert_eq!(micros(TimeFacts { at: a }), 2_000_000);
6163
assert_eq!(micros(TimeFacts { at: b }), 2_000_000);
6264
}
65+
66+
#[derive(drv::Input)]
67+
struct MidMapInput<'a> {
68+
pub by_mid: &'a HashMap<Mid, u32>,
69+
}
70+
71+
#[drv::memo(single)]
72+
fn mid_count(input: MidMapInput<'_>) -> usize {
73+
input.by_mid.len()
74+
}
75+
76+
#[test]
77+
fn mid_works_as_a_projected_hashmap_key() {
78+
let mut by_mid = HashMap::new();
79+
by_mid.insert(Mid::from("0"), 1u32);
80+
by_mid.insert(Mid::from("1"), 2u32);
81+
assert_eq!(mid_count(MidMapInput { by_mid: &by_mid }), 2);
82+
}

0 commit comments

Comments
 (0)