Skip to content

Commit 35ee2ff

Browse files
authored
372: Implement Eq and Hash for socket2::SockAddr
1 parent ac23d7d commit 35ee2ff

File tree

1 file changed

+192
-38
lines changed

1 file changed

+192
-38
lines changed

src/sockaddr.rs

+192-38
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use std::hash::Hash;
12
use std::mem::{self, size_of, MaybeUninit};
23
use std::net::{SocketAddr, SocketAddrV4, SocketAddrV6};
34
use std::path::Path;
@@ -312,44 +313,197 @@ impl fmt::Debug for SockAddr {
312313
}
313314
}
314315

315-
#[test]
316-
fn ipv4() {
317-
use std::net::Ipv4Addr;
318-
let std = SocketAddrV4::new(Ipv4Addr::new(1, 2, 3, 4), 9876);
319-
let addr = SockAddr::from(std);
320-
assert!(addr.is_ipv4());
321-
assert_eq!(addr.family(), AF_INET as sa_family_t);
322-
assert_eq!(addr.domain(), Domain::IPV4);
323-
assert_eq!(addr.len(), size_of::<sockaddr_in>() as socklen_t);
324-
assert_eq!(addr.as_socket(), Some(SocketAddr::V4(std)));
325-
assert_eq!(addr.as_socket_ipv4(), Some(std));
326-
assert!(addr.as_socket_ipv6().is_none());
327-
328-
let addr = SockAddr::from(SocketAddr::from(std));
329-
assert_eq!(addr.family(), AF_INET as sa_family_t);
330-
assert_eq!(addr.len(), size_of::<sockaddr_in>() as socklen_t);
331-
assert_eq!(addr.as_socket(), Some(SocketAddr::V4(std)));
332-
assert_eq!(addr.as_socket_ipv4(), Some(std));
333-
assert!(addr.as_socket_ipv6().is_none());
316+
impl PartialEq for SockAddr {
317+
fn eq(&self, other: &Self) -> bool {
318+
unsafe {
319+
let these_bytes: &[u8] = any_as_u8_slice(&self.storage, self.len as usize);
320+
let those_bytes: &[u8] = any_as_u8_slice(&other.storage, other.len as usize);
321+
these_bytes == those_bytes
322+
}
323+
}
324+
}
325+
326+
impl Eq for SockAddr {}
327+
328+
impl Hash for SockAddr {
329+
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
330+
unsafe {
331+
let these_bytes: &[u8] = any_as_u8_slice(&self.storage, self.len as usize);
332+
these_bytes.hash(state);
333+
}
334+
}
335+
}
336+
337+
unsafe fn any_as_u8_slice<T: Sized>(p: &T, size: usize) -> &[u8] {
338+
::std::slice::from_raw_parts((p as *const T) as *const u8, size)
334339
}
335340

336-
#[test]
337-
fn ipv6() {
338-
use std::net::Ipv6Addr;
339-
let std = SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), 9876, 11, 12);
340-
let addr = SockAddr::from(std);
341-
assert!(addr.is_ipv6());
342-
assert_eq!(addr.family(), AF_INET6 as sa_family_t);
343-
assert_eq!(addr.domain(), Domain::IPV6);
344-
assert_eq!(addr.len(), size_of::<sockaddr_in6>() as socklen_t);
345-
assert_eq!(addr.as_socket(), Some(SocketAddr::V6(std)));
346-
assert!(addr.as_socket_ipv4().is_none());
347-
assert_eq!(addr.as_socket_ipv6(), Some(std));
348-
349-
let addr = SockAddr::from(SocketAddr::from(std));
350-
assert_eq!(addr.family(), AF_INET6 as sa_family_t);
351-
assert_eq!(addr.len(), size_of::<sockaddr_in6>() as socklen_t);
352-
assert_eq!(addr.as_socket(), Some(SocketAddr::V6(std)));
353-
assert!(addr.as_socket_ipv4().is_none());
354-
assert_eq!(addr.as_socket_ipv6(), Some(std));
341+
#[cfg(test)]
342+
mod tests {
343+
use super::*;
344+
345+
#[test]
346+
fn ipv4() {
347+
use std::net::Ipv4Addr;
348+
let std = SocketAddrV4::new(Ipv4Addr::new(1, 2, 3, 4), 9876);
349+
let addr = SockAddr::from(std);
350+
assert!(addr.is_ipv4());
351+
assert_eq!(addr.family(), AF_INET as sa_family_t);
352+
assert_eq!(addr.domain(), Domain::IPV4);
353+
assert_eq!(addr.len(), size_of::<sockaddr_in>() as socklen_t);
354+
assert_eq!(addr.as_socket(), Some(SocketAddr::V4(std)));
355+
assert_eq!(addr.as_socket_ipv4(), Some(std));
356+
assert!(addr.as_socket_ipv6().is_none());
357+
358+
let addr = SockAddr::from(SocketAddr::from(std));
359+
assert_eq!(addr.family(), AF_INET as sa_family_t);
360+
assert_eq!(addr.len(), size_of::<sockaddr_in>() as socklen_t);
361+
assert_eq!(addr.as_socket(), Some(SocketAddr::V4(std)));
362+
assert_eq!(addr.as_socket_ipv4(), Some(std));
363+
assert!(addr.as_socket_ipv6().is_none());
364+
}
365+
366+
#[test]
367+
fn ipv6() {
368+
use std::net::Ipv6Addr;
369+
let std = SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), 9876, 11, 12);
370+
let addr = SockAddr::from(std);
371+
assert!(addr.is_ipv6());
372+
assert_eq!(addr.family(), AF_INET6 as sa_family_t);
373+
assert_eq!(addr.domain(), Domain::IPV6);
374+
assert_eq!(addr.len(), size_of::<sockaddr_in6>() as socklen_t);
375+
assert_eq!(addr.as_socket(), Some(SocketAddr::V6(std)));
376+
assert!(addr.as_socket_ipv4().is_none());
377+
assert_eq!(addr.as_socket_ipv6(), Some(std));
378+
379+
let addr = SockAddr::from(SocketAddr::from(std));
380+
assert_eq!(addr.family(), AF_INET6 as sa_family_t);
381+
assert_eq!(addr.len(), size_of::<sockaddr_in6>() as socklen_t);
382+
assert_eq!(addr.as_socket(), Some(SocketAddr::V6(std)));
383+
assert!(addr.as_socket_ipv4().is_none());
384+
assert_eq!(addr.as_socket_ipv6(), Some(std));
385+
}
386+
387+
#[test]
388+
fn ipv4_eq() {
389+
use std::net::Ipv4Addr;
390+
391+
let std1 = SocketAddrV4::new(Ipv4Addr::new(1, 2, 3, 4), 9876);
392+
let std2 = SocketAddrV4::new(Ipv4Addr::new(5, 6, 7, 8), 8765);
393+
394+
test_eq(
395+
SockAddr::from(std1),
396+
SockAddr::from(std1),
397+
SockAddr::from(std2),
398+
);
399+
}
400+
401+
#[test]
402+
fn ipv4_hash() {
403+
use std::net::Ipv4Addr;
404+
405+
let std1 = SocketAddrV4::new(Ipv4Addr::new(1, 2, 3, 4), 9876);
406+
let std2 = SocketAddrV4::new(Ipv4Addr::new(5, 6, 7, 8), 8765);
407+
408+
test_hash(
409+
SockAddr::from(std1),
410+
SockAddr::from(std1),
411+
SockAddr::from(std2),
412+
);
413+
}
414+
415+
#[test]
416+
fn ipv6_eq() {
417+
use std::net::Ipv6Addr;
418+
419+
let std1 = SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), 9876, 11, 12);
420+
let std2 = SocketAddrV6::new(Ipv6Addr::new(3, 4, 5, 6, 7, 8, 9, 0), 7654, 13, 14);
421+
422+
test_eq(
423+
SockAddr::from(std1),
424+
SockAddr::from(std1),
425+
SockAddr::from(std2),
426+
);
427+
}
428+
429+
#[test]
430+
fn ipv6_hash() {
431+
use std::net::Ipv6Addr;
432+
433+
let std1 = SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), 9876, 11, 12);
434+
let std2 = SocketAddrV6::new(Ipv6Addr::new(3, 4, 5, 6, 7, 8, 9, 0), 7654, 13, 14);
435+
436+
test_hash(
437+
SockAddr::from(std1),
438+
SockAddr::from(std1),
439+
SockAddr::from(std2),
440+
);
441+
}
442+
443+
#[test]
444+
fn ipv4_ipv6_eq() {
445+
use std::net::Ipv4Addr;
446+
use std::net::Ipv6Addr;
447+
448+
let std1 = SocketAddrV4::new(Ipv4Addr::new(1, 2, 3, 4), 9876);
449+
let std2 = SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), 9876, 11, 12);
450+
451+
test_eq(
452+
SockAddr::from(std1),
453+
SockAddr::from(std1),
454+
SockAddr::from(std2),
455+
);
456+
457+
test_eq(
458+
SockAddr::from(std2),
459+
SockAddr::from(std2),
460+
SockAddr::from(std1),
461+
);
462+
}
463+
464+
#[test]
465+
fn ipv4_ipv6_hash() {
466+
use std::net::Ipv4Addr;
467+
use std::net::Ipv6Addr;
468+
469+
let std1 = SocketAddrV4::new(Ipv4Addr::new(1, 2, 3, 4), 9876);
470+
let std2 = SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), 9876, 11, 12);
471+
472+
test_hash(
473+
SockAddr::from(std1),
474+
SockAddr::from(std1),
475+
SockAddr::from(std2),
476+
);
477+
478+
test_hash(
479+
SockAddr::from(std2),
480+
SockAddr::from(std2),
481+
SockAddr::from(std1),
482+
);
483+
}
484+
485+
#[allow(clippy::eq_op)] // allow a0 == a0 check
486+
fn test_eq(a0: SockAddr, a1: SockAddr, b: SockAddr) {
487+
assert!(a0 == a0);
488+
assert!(a0 == a1);
489+
assert!(a1 == a0);
490+
assert!(a0 != b);
491+
assert!(b != a0);
492+
}
493+
494+
fn test_hash(a0: SockAddr, a1: SockAddr, b: SockAddr) {
495+
assert!(calculate_hash(&a0) == calculate_hash(&a0));
496+
assert!(calculate_hash(&a0) == calculate_hash(&a1));
497+
// technically unequal values can have the same hash, in this case x != z and both have different hashes
498+
assert!(calculate_hash(&a0) != calculate_hash(&b));
499+
}
500+
501+
fn calculate_hash(x: &SockAddr) -> u64 {
502+
use std::collections::hash_map::DefaultHasher;
503+
use std::hash::Hasher;
504+
505+
let mut hasher = DefaultHasher::new();
506+
x.hash(&mut hasher);
507+
hasher.finish()
508+
}
355509
}

0 commit comments

Comments
 (0)