mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer-rs.git
synced 2025-04-15 04:14:07 +00:00
Merge branch 'hash' into 'main'
implement Hash on Structure and Caps See merge request gstreamer/gstreamer-rs!1639
This commit is contained in:
commit
c7e93ba7ba
3 changed files with 200 additions and 0 deletions
|
@ -1259,6 +1259,28 @@ impl PartialEq for CapsRef {
|
|||
|
||||
impl Eq for CapsRef {}
|
||||
|
||||
impl std::hash::Hash for CapsRef {
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
if self.is_any() {
|
||||
"ANY".hash(state);
|
||||
} else if self.is_empty() {
|
||||
"EMPTY".hash(state);
|
||||
} else {
|
||||
// do no sort as structure order matters
|
||||
for (s, feature) in self.iter_with_features() {
|
||||
s.hash(state);
|
||||
feature.hash(state);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::hash::Hash for Caps {
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
self.as_ref().hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
pub enum NoFeature {}
|
||||
pub enum HasFeatures {}
|
||||
|
||||
|
@ -1761,4 +1783,62 @@ mod tests {
|
|||
|
||||
assert_eq!(format!("{caps:?}"), "Caps(video/x-raw(memory:SystemMemory) { array: Array([(gchararray) \"a\", (gchararray) \"b\", (gchararray) \"c\"]), list: List([(gchararray) \"d\", (gchararray) \"e\", (gchararray) \"f\"]) })");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hash() {
|
||||
crate::init().unwrap();
|
||||
|
||||
use std::hash::BuildHasher;
|
||||
let bh = std::hash::RandomState::new();
|
||||
|
||||
let caps = Caps::builder("video/x-raw").build();
|
||||
assert_eq!(bh.hash_one(&caps), bh.hash_one(&caps));
|
||||
|
||||
let caps_any = Caps::new_any();
|
||||
let caps_empty = Caps::new_empty();
|
||||
assert_eq!(bh.hash_one(&caps_any), bh.hash_one(&caps_any));
|
||||
assert_eq!(bh.hash_one(&caps_empty), bh.hash_one(&caps_empty));
|
||||
assert_ne!(bh.hash_one(&caps_any), bh.hash_one(&caps_empty));
|
||||
|
||||
// Same caps but fields in a different order
|
||||
let caps_a = Caps::builder("video/x-raw")
|
||||
.field("width", 1920u32)
|
||||
.field("height", 1080u32)
|
||||
.build();
|
||||
let caps_b = Caps::builder("video/x-raw")
|
||||
.field("height", 1080u32)
|
||||
.field("width", 1920u32)
|
||||
.build();
|
||||
assert_eq!(bh.hash_one(&caps_a), bh.hash_one(&caps_a));
|
||||
assert_eq!(bh.hash_one(&caps_b), bh.hash_one(&caps_b));
|
||||
assert_eq!(bh.hash_one(&caps_a), bh.hash_one(&caps_b));
|
||||
|
||||
// Same fields but different feature
|
||||
let caps_a = Caps::builder("video/x-raw")
|
||||
.features(["memory:DMABuf"])
|
||||
.field("width", 1920u32)
|
||||
.field("height", 1080u32)
|
||||
.build();
|
||||
let caps_b = Caps::builder("video/x-raw")
|
||||
.features(["memory:GLMemory"])
|
||||
.field("height", 1080u32)
|
||||
.field("width", 1920u32)
|
||||
.build();
|
||||
assert_eq!(bh.hash_one(&caps_a), bh.hash_one(&caps_a));
|
||||
assert_eq!(bh.hash_one(&caps_b), bh.hash_one(&caps_b));
|
||||
assert_ne!(bh.hash_one(&caps_a), bh.hash_one(&caps_b));
|
||||
|
||||
// Caps have the same structures but in different order, so they are actually different
|
||||
let caps_a = Caps::builder_full()
|
||||
.structure(Structure::builder("audio/x-raw").build())
|
||||
.structure(Structure::builder("video/x-raw").build())
|
||||
.build();
|
||||
let caps_b = Caps::builder_full()
|
||||
.structure(Structure::builder("video/x-raw").build())
|
||||
.structure(Structure::builder("audio/x-raw").build())
|
||||
.build();
|
||||
assert_eq!(bh.hash_one(&caps_a), bh.hash_one(&caps_a));
|
||||
assert_eq!(bh.hash_one(&caps_b), bh.hash_one(&caps_b));
|
||||
assert_ne!(bh.hash_one(&caps_a), bh.hash_one(&caps_b));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -882,6 +882,28 @@ impl ToOwned for CapsFeaturesRef {
|
|||
}
|
||||
}
|
||||
|
||||
impl std::hash::Hash for CapsFeaturesRef {
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
use itertools::Itertools;
|
||||
|
||||
if self.is_any() {
|
||||
"ANY".hash(state);
|
||||
} else if self.is_empty() {
|
||||
"EMPTY".hash(state);
|
||||
} else {
|
||||
for f in self.iter().sorted() {
|
||||
f.hash(state);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::hash::Hash for CapsFeatures {
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
self.as_ref().hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Sync for CapsFeaturesRef {}
|
||||
unsafe impl Send for CapsFeaturesRef {}
|
||||
|
||||
|
@ -1009,4 +1031,38 @@ mod tests {
|
|||
assert!(cf.contains_by_id(overlay_comp));
|
||||
assert!(!cf.contains("memory:GLMemory"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hash() {
|
||||
crate::init().unwrap();
|
||||
|
||||
use std::hash::BuildHasher;
|
||||
let bh = std::hash::RandomState::new();
|
||||
|
||||
let any = CapsFeatures::new_any();
|
||||
let empty = CapsFeatures::new_empty();
|
||||
assert_eq!(bh.hash_one(&any), bh.hash_one(&any));
|
||||
assert_eq!(bh.hash_one(&empty), bh.hash_one(&empty));
|
||||
assert_ne!(bh.hash_one(&any), bh.hash_one(&empty));
|
||||
|
||||
// Different names
|
||||
let cf1 = CapsFeatures::from(gstr!("memory:DMABuf"));
|
||||
let cf2 = CapsFeatures::from(gstr!("memory:GLMemory"));
|
||||
assert_eq!(bh.hash_one(&cf1), bh.hash_one(&cf1));
|
||||
assert_eq!(bh.hash_one(&cf2), bh.hash_one(&cf2));
|
||||
assert_ne!(bh.hash_one(&cf1), bh.hash_one(&cf2));
|
||||
|
||||
// Same features, different order
|
||||
let cf1 = CapsFeatures::from([
|
||||
gstr!("memory:DMABuf"),
|
||||
gstr!("meta:GstVideoOverlayComposition"),
|
||||
]);
|
||||
let cf2 = CapsFeatures::from([
|
||||
gstr!("meta:GstVideoOverlayComposition"),
|
||||
gstr!("memory:DMABuf"),
|
||||
]);
|
||||
assert_eq!(bh.hash_one(&cf1), bh.hash_one(&cf1));
|
||||
assert_eq!(bh.hash_one(&cf2), bh.hash_one(&cf2));
|
||||
assert_eq!(bh.hash_one(&cf1), bh.hash_one(&cf2));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1984,6 +1984,28 @@ impl std::iter::Extend<(glib::Quark, SendValue)> for StructureRef {
|
|||
}
|
||||
}
|
||||
|
||||
impl std::hash::Hash for StructureRef {
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
// Use the string serialization for hashing but first sort fields by values so structures
|
||||
// with the same fields but in different orders have the same hash.
|
||||
use itertools::Itertools;
|
||||
|
||||
let sorted_s = Structure::from_iter(
|
||||
self.name(),
|
||||
self.iter()
|
||||
.sorted_by(|(field_a, _), (field_b, _)| field_a.cmp(field_b))
|
||||
.map(|(f, v)| (f, v.clone())),
|
||||
);
|
||||
sorted_s.to_string().hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl std::hash::Hash for Structure {
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
self.as_ref().hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[must_use = "The builder must be built to be used"]
|
||||
pub struct Builder {
|
||||
|
@ -2526,4 +2548,46 @@ mod tests {
|
|||
|
||||
assert_eq!(s.field_ids().collect::<Vec<_>>(), vec![&f1, &f2]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hash() {
|
||||
crate::init().unwrap();
|
||||
|
||||
use std::hash::BuildHasher;
|
||||
let bh = std::hash::RandomState::new();
|
||||
|
||||
// Different names
|
||||
let s1 = Structure::builder("test1").build();
|
||||
let s2 = Structure::builder("test2").build();
|
||||
assert_eq!(bh.hash_one(&s1), bh.hash_one(&s1));
|
||||
assert_eq!(bh.hash_one(&s2), bh.hash_one(&s2));
|
||||
assert_ne!(bh.hash_one(&s1), bh.hash_one(&s2));
|
||||
|
||||
// Same name different fields
|
||||
let s1 = Structure::builder("test").field("a", 1u32).build();
|
||||
let s2 = Structure::builder("test").field("b", 1u32).build();
|
||||
assert_eq!(bh.hash_one(&s1), bh.hash_one(&s1));
|
||||
assert_eq!(bh.hash_one(&s2), bh.hash_one(&s2));
|
||||
assert_ne!(bh.hash_one(&s1), bh.hash_one(&s2));
|
||||
|
||||
// Same name different field values
|
||||
let s1 = Structure::builder("test").field("a", 1u32).build();
|
||||
let s2 = Structure::builder("test").field("a", 2u32).build();
|
||||
assert_eq!(bh.hash_one(&s1), bh.hash_one(&s1));
|
||||
assert_eq!(bh.hash_one(&s2), bh.hash_one(&s2));
|
||||
assert_ne!(bh.hash_one(&s1), bh.hash_one(&s2));
|
||||
|
||||
// Same structure but fields in a different order
|
||||
let s1 = Structure::builder("test")
|
||||
.field("a", 1u32)
|
||||
.field("b", 2u32)
|
||||
.build();
|
||||
let s2 = Structure::builder("test")
|
||||
.field("b", 2u32)
|
||||
.field("a", 1u32)
|
||||
.build();
|
||||
assert_eq!(bh.hash_one(&s1), bh.hash_one(&s1));
|
||||
assert_eq!(bh.hash_one(&s2), bh.hash_one(&s2));
|
||||
assert_eq!(bh.hash_one(&s1), bh.hash_one(&s2));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue