mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer-rs.git
synced 2025-09-02 01:43:49 +00:00
gstreamer: structure: implement Hash
Will be used to implement Hash on Caps. Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1639>
This commit is contained in:
parent
d1ad651548
commit
f9f85ae75e
1 changed files with 74 additions and 0 deletions
|
@ -1984,6 +1984,37 @@ impl std::iter::Extend<(glib::Quark, SendValue)> for StructureRef {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Need gst_value_hash from 1.28
|
||||||
|
#[cfg(feature = "v1_28")]
|
||||||
|
impl std::hash::Hash for StructureRef {
|
||||||
|
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||||
|
use crate::value::GstValueExt;
|
||||||
|
use std::hash::{DefaultHasher, Hasher};
|
||||||
|
|
||||||
|
let name = self.name();
|
||||||
|
name.hash(state);
|
||||||
|
|
||||||
|
// re-implement gst_hash_structure() so the hashing is not depending on the fields order.
|
||||||
|
let mut fields_hash = 0;
|
||||||
|
for (field, value) in self.iter() {
|
||||||
|
let mut field_hasher = DefaultHasher::new();
|
||||||
|
field.hash(&mut field_hasher);
|
||||||
|
let value_hash = value.hash().unwrap();
|
||||||
|
value_hash.hash(&mut field_hasher);
|
||||||
|
|
||||||
|
fields_hash ^= field_hasher.finish();
|
||||||
|
}
|
||||||
|
fields_hash.hash(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "v1_28")]
|
||||||
|
impl std::hash::Hash for Structure {
|
||||||
|
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||||
|
self.as_ref().hash(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[must_use = "The builder must be built to be used"]
|
#[must_use = "The builder must be built to be used"]
|
||||||
pub struct Builder {
|
pub struct Builder {
|
||||||
|
@ -2526,4 +2557,47 @@ mod tests {
|
||||||
|
|
||||||
assert_eq!(s.field_ids().collect::<Vec<_>>(), vec![&f1, &f2]);
|
assert_eq!(s.field_ids().collect::<Vec<_>>(), vec![&f1, &f2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "v1_28")]
|
||||||
|
#[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