|
3 | 3 | //! the message type rather than the actor type. |
4 | 4 |
|
5 | 5 | use std::fmt; |
| 6 | +use std::hash::{Hash, Hasher}; |
6 | 7 |
|
7 | 8 | use crate::address::{ActorJoinHandle, Address}; |
8 | 9 | use crate::chan::RefCounter; |
@@ -207,6 +208,17 @@ where |
207 | 208 | } |
208 | 209 | } |
209 | 210 |
|
| 211 | +impl<M, R, Rc: RefCounter> Hash for MessageChannel<M, R, Rc> |
| 212 | +where |
| 213 | + M: Send + 'static, |
| 214 | + R: Send + 'static, |
| 215 | + Rc: Send + 'static, |
| 216 | +{ |
| 217 | + fn hash<H: Hasher>(&self, state: &mut H) { |
| 218 | + self.inner.hash(state) |
| 219 | + } |
| 220 | +} |
| 221 | + |
210 | 222 | impl<M, R, Rc> Clone for MessageChannel<M, R, Rc> |
211 | 223 | where |
212 | 224 | R: Send + 'static, |
@@ -295,6 +307,8 @@ trait MessageChannelTrait<M, Rc> { |
295 | 307 | fn to_either( |
296 | 308 | &self, |
297 | 309 | ) -> Box<dyn MessageChannelTrait<M, Either, Return = Self::Return> + Send + Sync + 'static>; |
| 310 | + |
| 311 | + fn hash(&self, state: &mut dyn Hasher); |
298 | 312 | } |
299 | 313 |
|
300 | 314 | impl<A, R, M, Rc: RefCounter> MessageChannelTrait<M, Rc> for Address<A, Rc> |
@@ -366,4 +380,101 @@ where |
366 | 380 | { |
367 | 381 | Box::new(Address(self.0.to_tx_either())) |
368 | 382 | } |
| 383 | + |
| 384 | + fn hash(&self, state: &mut dyn Hasher) { |
| 385 | + state.write_usize(self.0.inner_ptr() as *const _ as usize); |
| 386 | + state.write_u8(self.0.is_strong() as u8); |
| 387 | + state.finish(); |
| 388 | + } |
| 389 | +} |
| 390 | + |
| 391 | +#[cfg(test)] |
| 392 | +mod test { |
| 393 | + use std::hash::{Hash, Hasher}; |
| 394 | + |
| 395 | + use crate::{Actor, Handler, Mailbox}; |
| 396 | + |
| 397 | + type TestMessageChannel = super::MessageChannel<TestMessage, ()>; |
| 398 | + |
| 399 | + struct TestActor; |
| 400 | + struct TestMessage; |
| 401 | + |
| 402 | + impl Actor for TestActor { |
| 403 | + type Stop = (); |
| 404 | + |
| 405 | + async fn stopped(self) -> Self::Stop {} |
| 406 | + } |
| 407 | + |
| 408 | + impl Handler<TestMessage> for TestActor { |
| 409 | + type Return = (); |
| 410 | + |
| 411 | + async fn handle(&mut self, _: TestMessage, _: &mut crate::Context<Self>) -> Self::Return {} |
| 412 | + } |
| 413 | + |
| 414 | + struct RecordingHasher(Vec<u8>); |
| 415 | + |
| 416 | + impl RecordingHasher { |
| 417 | + fn record_hash<H: Hash>(value: &H) -> Vec<u8> { |
| 418 | + let mut h = Self(Vec::new()); |
| 419 | + value.hash(&mut h); |
| 420 | + assert!(!h.0.is_empty(), "the hash data not be empty"); |
| 421 | + h.0 |
| 422 | + } |
| 423 | + } |
| 424 | + |
| 425 | + impl Hasher for RecordingHasher { |
| 426 | + fn finish(&self) -> u64 { |
| 427 | + 0 |
| 428 | + } |
| 429 | + |
| 430 | + fn write(&mut self, bytes: &[u8]) { |
| 431 | + self.0.extend_from_slice(bytes) |
| 432 | + } |
| 433 | + } |
| 434 | + |
| 435 | + #[test] |
| 436 | + fn hashcode() { |
| 437 | + let (a1, _) = Mailbox::<TestActor>::unbounded(); |
| 438 | + let c1 = TestMessageChannel::new(a1.clone()); |
| 439 | + |
| 440 | + let h1 = RecordingHasher::record_hash(&c1); |
| 441 | + let h2 = RecordingHasher::record_hash(&c1.clone()); |
| 442 | + let h3 = RecordingHasher::record_hash(&TestMessageChannel::new(a1)); |
| 443 | + |
| 444 | + assert_eq!(h1, h2, "hashes from cloned channels should match"); |
| 445 | + assert_eq!( |
| 446 | + h1, h3, |
| 447 | + "hashes channels created against the same address should match" |
| 448 | + ); |
| 449 | + |
| 450 | + let h4 = RecordingHasher::record_hash(&TestMessageChannel::new( |
| 451 | + Mailbox::<TestActor>::unbounded().0, |
| 452 | + )); |
| 453 | + |
| 454 | + assert_ne!( |
| 455 | + h1, h4, |
| 456 | + "hashes from channels created against different addresses should differ" |
| 457 | + ); |
| 458 | + } |
| 459 | + |
| 460 | + #[test] |
| 461 | + fn partial_eq() { |
| 462 | + let (a1, _) = Mailbox::<TestActor>::unbounded(); |
| 463 | + let c1 = TestMessageChannel::new(a1.clone()); |
| 464 | + let c2 = c1.clone(); |
| 465 | + let c3 = TestMessageChannel::new(a1); |
| 466 | + |
| 467 | + assert_eq!(c1, c2, "cloned channels should match"); |
| 468 | + assert_eq!( |
| 469 | + c1, c3, |
| 470 | + "channels created against the same address should match" |
| 471 | + ); |
| 472 | + |
| 473 | + let c4 = TestMessageChannel::new(Mailbox::<TestActor>::unbounded().0); |
| 474 | + |
| 475 | + assert_ne!( |
| 476 | + c1, c4, |
| 477 | + "channels created against different addresses should differ" |
| 478 | + ); |
| 479 | + } |
369 | 480 | } |
0 commit comments