1use super::*;
2use crate::{
3 messaging::{DispatchData, DispatchEnvelope, MsgEnvelope, SerialisedFrame},
4 net::buffers::ChunkRef,
5};
6use std::{
7 convert::TryFrom,
8 error::Error,
9 fmt::{self, Debug},
10 net::{AddrParseError, IpAddr, SocketAddr},
11 ops::Div,
12 str::FromStr,
13};
14use uuid::Uuid;
15
16#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
24#[repr(u8)]
25pub enum Transport {
26 Local = 0b00,
28 Tcp = 0b01,
30 Udp = 0b10,
32}
33
34impl Transport {
35 pub fn is_local(&self) -> bool {
37 matches!(*self, Transport::Local)
38 }
39
40 pub fn is_remote(&self) -> bool {
42 !self.is_local()
43 }
44}
45
46impl fmt::Display for Transport {
47 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
48 match self {
49 &Transport::Local => write!(fmt, "local"),
50 &Transport::Tcp => write!(fmt, "tcp"),
51 &Transport::Udp => write!(fmt, "udp"),
52 }
53 }
54}
55
56impl FromStr for Transport {
57 type Err = TransportParseError;
58
59 fn from_str(s: &str) -> Result<Transport, TransportParseError> {
60 match s {
61 "local" => Ok(Transport::Local),
62 "tcp" => Ok(Transport::Tcp),
63 "udp" => Ok(Transport::Udp),
64 _ => Err(TransportParseError),
65 }
66 }
67}
68
69#[derive(Debug, PartialEq, Eq, Clone, Hash)]
71pub struct TransportParseError;
72
73impl fmt::Display for TransportParseError {
74 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
75 fmt.write_str("TransportParseError")
76 }
77}
78
79impl Error for TransportParseError {
80 fn description(&self) -> &str {
81 "Transport must be one of [local,tcp,udp]"
82 }
83}
84
85#[derive(Debug, PartialEq, Eq, Clone)]
87pub enum PathParseError {
88 Form(String),
90 Transport(TransportParseError),
92 Addr(AddrParseError),
94 IllegalCharacter(char),
96}
97
98impl fmt::Display for PathParseError {
99 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
100 match self {
101 PathParseError::Form(s) => write!(fmt, "Invalid formatting: {}", s),
102 PathParseError::Transport(e) => write!(fmt, "Could not parse transport: {}", e),
103 PathParseError::Addr(e) => write!(fmt, "Could not parse address: {}", e),
104 PathParseError::IllegalCharacter(c) => {
105 write!(fmt, "The path contains an illegal character: {}", c)
106 }
107 }
108 }
109}
110
111impl Error for PathParseError {
112 fn description(&self) -> &str {
113 "Path could not be parsed"
114 }
115
116 fn cause(&self) -> Option<&dyn Error> {
117 match self {
118 PathParseError::Form(_) => None,
119 PathParseError::Transport(e) => Some(e),
120 PathParseError::Addr(e) => Some(e),
121 PathParseError::IllegalCharacter(_) => None,
122 }
123 }
124}
125
126impl From<TransportParseError> for PathParseError {
127 fn from(e: TransportParseError) -> PathParseError {
128 PathParseError::Transport(e)
129 }
130}
131
132impl From<AddrParseError> for PathParseError {
133 fn from(e: AddrParseError) -> PathParseError {
134 PathParseError::Addr(e)
135 }
136}
137
138#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
142pub struct SystemPath {
143 protocol: Transport,
144 address: IpAddr,
146 port: u16,
147}
148
149impl SystemPath {
150 pub fn new(protocol: Transport, address: IpAddr, port: u16) -> SystemPath {
152 SystemPath {
153 protocol,
154 address,
155 port,
156 }
157 }
158
159 pub fn with_socket(protocol: Transport, socket: SocketAddr) -> SystemPath {
161 SystemPath {
162 protocol,
163 address: socket.ip(),
164 port: socket.port(),
165 }
166 }
167
168 pub fn protocol(&self) -> Transport {
170 self.protocol
171 }
172
173 pub fn address(&self) -> &IpAddr {
175 &self.address
176 }
177
178 pub fn port(&self) -> u16 {
180 self.port
181 }
182
183 pub fn into_named_with_string(self, path: &str) -> Result<NamedPath, PathParseError> {
188 let parsed = parse_path(path);
189 self.into_named_with_vec(parsed)
190 }
191
192 pub fn socket_address(&self) -> SocketAddr {
194 SocketAddr::new(self.address, self.port)
195 }
196
197 pub fn into_named_with_vec(self, path: Vec<String>) -> Result<NamedPath, PathParseError> {
202 validate_lookup_path(&path)?;
203 let named = NamedPath::with_system(self, path);
204 Ok(named)
205 }
206
207 pub fn into_unique(self, id: Uuid) -> UniquePath {
209 UniquePath::with_system(self, id)
210 }
211}
212
213impl fmt::Display for SystemPath {
214 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
215 write!(fmt, "{}://{}:{}", self.protocol, self.address, self.port)
216 }
217}
218
219pub trait SystemField {
221 fn system(&self) -> &SystemPath;
223
224 fn protocol(&self) -> Transport {
226 self.system().protocol()
227 }
228
229 fn address(&self) -> &IpAddr {
231 self.system().address()
232 }
233
234 fn port(&self) -> u16 {
236 self.system().port()
237 }
238}
239
240impl SystemField for SystemPath {
241 fn system(&self) -> &SystemPath {
242 self
243 }
244}
245
246pub trait ActorPathFactory {
248 fn actor_path(&self) -> ActorPath;
250}
251
252pub struct DispatchingPath<'a, 'b> {
263 path: &'a ActorPath,
264 ctx: &'b dyn Dispatching,
265}
266
267impl Dispatching for DispatchingPath<'_, '_> {
268 fn dispatcher_ref(&self) -> DispatcherRef {
269 self.ctx.dispatcher_ref()
270 }
271}
272
273impl ActorPathFactory for DispatchingPath<'_, '_> {
274 fn actor_path(&self) -> ActorPath {
275 self.path.clone()
276 }
277}
278
279#[derive(Clone, Debug)]
286#[repr(u8)]
287#[derive(PartialEq, Eq, Hash, PartialOrd, Ord)]
288pub enum ActorPath {
289 Unique(UniquePath),
298 Named(NamedPath),
308}
309
310impl ActorPath {
311 pub fn tell<S, B>(&self, m: B, from: &S) -> ()
330 where
331 S: ActorPathFactory + Dispatching,
332 B: Into<Box<dyn Serialisable>>,
333 {
334 let mut src = from.actor_path();
335 src.set_protocol(self.protocol());
336 self.tell_with_sender(m, from, src)
337 }
338
339 pub fn tell_with_sender<B, D>(&self, m: B, dispatch: &D, from: ActorPath) -> ()
353 where
354 B: Into<Box<dyn Serialisable>>,
355 D: Dispatching,
356 {
357 let msg: Box<dyn Serialisable> = m.into();
358 let dst = self.clone();
359 let env = DispatchEnvelope::Msg {
360 src: from.clone(),
361 dst: dst.clone(),
362 msg: DispatchData::Lazy(msg, from, dst),
363 };
364 dispatch.dispatcher_ref().enqueue(MsgEnvelope::Typed(env))
365 }
366
367 pub fn tell_serialised<CD, B>(&self, m: B, from: &CD) -> Result<(), SerError>
372 where
373 CD: ComponentTraits + ComponentLifecycle,
374 B: Serialisable + 'static,
375 {
376 let mut src = from.actor_path();
377 src.set_protocol(self.protocol());
378 self.tell_serialised_with_sender(m, from, src)
379 }
380
381 pub fn tell_serialised_with_sender<CD, B>(
386 &self,
387 m: B,
388 dispatch: &CD,
389 from: ActorPath,
390 ) -> Result<(), SerError>
391 where
392 CD: ComponentTraits + ComponentLifecycle,
393 B: Serialisable + 'static,
394 {
395 if self.protocol() == Transport::Local {
396 self.tell_with_sender(m, dispatch, from);
398 Ok(())
399 } else {
400 dispatch.ctx().with_buffer(|buffer| {
401 let mut buf = buffer.get_buffer_encoder()?;
402 let msg =
403 crate::serialisation::ser_helpers::serialise_msg(&from, self, &m, &mut buf)?;
404 let env = DispatchEnvelope::Msg {
405 src: from,
406 dst: self.clone(),
407 msg: DispatchData::Serialised(SerialisedFrame::ChunkLease(msg)),
408 };
409 dispatch.dispatcher_ref().enqueue(MsgEnvelope::Typed(env));
410 Ok(())
411 })
412 }
413 }
414
415 pub fn tell_preserialised<CD>(&self, content: ChunkRef, from: &CD) -> Result<(), SerError>
423 where
424 CD: ComponentTraits + ComponentLifecycle,
425 {
426 let mut src = from.actor_path();
427 src.set_protocol(self.protocol());
428 self.tell_preserialised_with_sender(content, from, src)
429 }
430
431 pub fn tell_preserialised_with_sender<CD: ComponentTraits + ComponentLifecycle>(
438 &self,
439 content: ChunkRef,
440 dispatch: &CD,
441 from: ActorPath,
442 ) -> Result<(), SerError> {
443 dispatch.ctx().with_buffer(|buffer| {
444 let mut buf = buffer.get_buffer_encoder()?;
445 let msg = crate::serialisation::ser_helpers::serialise_msg_with_preserialised(
446 &from, self, content, &mut buf,
447 )?;
448 let env = DispatchEnvelope::Msg {
449 src: from,
450 dst: self.clone(),
451 msg: DispatchData::Serialised(SerialisedFrame::ChunkRef(msg)),
452 };
453 dispatch.dispatcher_ref().enqueue(MsgEnvelope::Typed(env));
454 Ok(())
455 })
456 }
457
458 pub fn forward_with_original_sender<D>(
463 &self,
464 mut serialised_message: NetMessage,
465 dispatcher: &D,
466 ) -> ()
467 where
468 D: Dispatching,
469 {
470 serialised_message.receiver = self.clone();
471 let env = DispatchEnvelope::ForwardedMsg {
472 msg: serialised_message,
473 };
474 dispatcher.dispatcher_ref().enqueue(MsgEnvelope::Typed(env));
475 }
476
477 pub fn forward_with_sender<D>(
479 &self,
480 mut serialised_message: NetMessage,
481 dispatch: &D,
482 from: ActorPath,
483 ) -> ()
484 where
485 D: Dispatching,
486 {
487 serialised_message.receiver = self.clone();
488 serialised_message.sender = from;
489 let env = DispatchEnvelope::ForwardedMsg {
490 msg: serialised_message,
491 };
492 dispatch.dispatcher_ref().enqueue(MsgEnvelope::Typed(env));
493 }
494
495 pub fn using_dispatcher<'a, 'b>(
504 &'a self,
505 disp: &'b dyn Dispatching,
506 ) -> DispatchingPath<'a, 'b> {
507 DispatchingPath {
508 path: self,
509 ctx: disp,
510 }
511 }
512
513 fn system_mut(&mut self) -> &mut SystemPath {
514 match self {
515 ActorPath::Unique(ref mut up) => up.system_mut(),
516 ActorPath::Named(ref mut np) => np.system_mut(),
517 }
518 }
519
520 pub fn set_protocol(&mut self, proto: Transport) {
522 self.system_mut().protocol = proto;
523 }
524
525 pub fn via_udp(&mut self) {
527 self.set_protocol(Transport::Udp);
528 }
529
530 pub fn via_tcp(&mut self) {
532 self.set_protocol(Transport::Tcp);
533 }
534
535 pub fn via_local(&mut self) {
537 self.set_protocol(Transport::Local);
538 }
539
540 pub fn named(self) -> Option<NamedPath> {
544 match self {
545 ActorPath::Named(p) => Some(p),
546 _ => None,
547 }
548 }
549
550 pub fn unwrap_named(self) -> NamedPath {
554 self.named().unwrap()
555 }
556
557 pub fn unique(self) -> Option<UniquePath> {
561 match self {
562 ActorPath::Unique(p) => Some(p),
563 _ => None,
564 }
565 }
566
567 pub fn unwrap_unique(self) -> UniquePath {
571 self.unique().unwrap()
572 }
573}
574
575impl SystemField for ActorPath {
576 fn system(&self) -> &SystemPath {
577 match self {
578 ActorPath::Unique(up) => up.system(),
579 ActorPath::Named(np) => np.system(),
580 }
581 }
582}
583
584impl From<(SystemPath, Uuid)> for ActorPath {
585 fn from(t: (SystemPath, Uuid)) -> ActorPath {
586 ActorPath::Unique(UniquePath {
587 system: t.0,
588 id: t.1,
589 })
590 }
591}
592
593impl From<UniquePath> for ActorPath {
594 fn from(p: UniquePath) -> ActorPath {
595 ActorPath::Unique(p)
596 }
597}
598
599impl From<NamedPath> for ActorPath {
600 fn from(p: NamedPath) -> ActorPath {
601 ActorPath::Named(p)
602 }
603}
604
605pub const PATH_SEP: char = '/';
611pub const UNIQUE_PATH_SEP: char = '#';
617pub const BROADCAST_MARKER: char = '*';
624pub const SELECT_MARKER: char = '?';
631
632impl fmt::Display for ActorPath {
633 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
634 match self {
635 ActorPath::Named(np) => {
636 let path = np.path.iter().fold(String::new(), |mut acc, arg| {
637 acc.push(PATH_SEP);
638 acc.push_str(arg);
639 acc
640 });
641 write!(fmt, "{}{}", np.system, path)
642 }
643 ActorPath::Unique(up) => write!(fmt, "{}{}{}", up.system, UNIQUE_PATH_SEP, up.id),
644 }
645 }
646}
647
648impl TryFrom<String> for ActorPath {
649 type Error = PathParseError;
650
651 fn try_from(s: String) -> Result<Self, Self::Error> {
652 let p = ActorPath::from_str(&s)?;
653 Ok(p)
654 }
655}
656
657impl FromStr for ActorPath {
658 type Err = PathParseError;
659
660 fn from_str(s: &str) -> Result<Self, Self::Err> {
661 if s.contains(UNIQUE_PATH_SEP) {
662 let p = UniquePath::from_str(s)?;
663 Ok(ActorPath::Unique(p))
664 } else {
665 let p = NamedPath::from_str(s)?;
666 Ok(ActorPath::Named(p))
667 }
668 }
669}
670
671#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
680pub struct UniquePath {
681 system: SystemPath,
682 id: Uuid,
683}
684
685impl UniquePath {
686 pub fn new(protocol: Transport, address: IpAddr, port: u16, id: Uuid) -> UniquePath {
688 UniquePath {
689 system: SystemPath::new(protocol, address, port),
690 id,
691 }
692 }
693
694 pub fn with_system(system: SystemPath, id: Uuid) -> UniquePath {
696 UniquePath { system, id }
697 }
698
699 pub fn with_socket(protocol: Transport, socket: SocketAddr, id: Uuid) -> UniquePath {
701 UniquePath {
702 system: SystemPath::with_socket(protocol, socket),
703 id,
704 }
705 }
706
707 pub fn id(&self) -> Uuid {
709 self.id
710 }
711
712 pub fn system_mut(&mut self) -> &mut SystemPath {
714 &mut self.system
715 }
716}
717
718impl TryFrom<String> for UniquePath {
719 type Error = PathParseError;
720
721 fn try_from(s: String) -> Result<Self, Self::Error> {
722 let p = UniquePath::from_str(&s)?;
723 Ok(p)
724 }
725}
726
727impl FromStr for UniquePath {
728 type Err = PathParseError;
729
730 fn from_str(s: &str) -> Result<Self, Self::Err> {
731 let parts: Vec<&str> = s.split("://").collect();
732 if parts.len() != 2 {
734 return Err(PathParseError::Form(s.to_string()));
735 }
736 let proto: Transport = parts[0].parse()?;
737 let parts: Vec<&str> = parts[1].split(UNIQUE_PATH_SEP).collect();
738 if parts.len() != 2 {
740 return Err(PathParseError::Form(s.to_string()));
741 }
742 let socket = SocketAddr::from_str(parts[0])?;
743 let uuid =
744 Uuid::from_str(parts[1]).map_err(|_parse_err| PathParseError::Form(s.to_string()))?;
745
746 Ok(UniquePath::with_socket(proto, socket, uuid))
747 }
748}
749
750impl SystemField for UniquePath {
751 fn system(&self) -> &SystemPath {
752 &self.system
753 }
754}
755
756#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
766pub struct NamedPath {
767 system: SystemPath,
768 path: Vec<String>,
769}
770
771impl NamedPath {
772 pub fn new(protocol: Transport, address: IpAddr, port: u16, path: Vec<String>) -> NamedPath {
777 debug_assert!(
778 crate::actors::validate_lookup_path(&path).is_ok(),
779 "Path contains illegal characters: {:?}",
780 path
781 );
782 NamedPath {
783 system: SystemPath::new(protocol, address, port),
784 path,
785 }
786 }
787
788 pub fn with_socket(protocol: Transport, socket: SocketAddr, path: Vec<String>) -> NamedPath {
793 debug_assert!(
794 crate::actors::validate_lookup_path(&path).is_ok(),
795 "Path contains illegal characters: {:?}",
796 path
797 );
798 NamedPath {
799 system: SystemPath::with_socket(protocol, socket),
800 path,
801 }
802 }
803
804 pub fn with_system(system: SystemPath, path: Vec<String>) -> NamedPath {
809 debug_assert!(
810 crate::actors::validate_lookup_path(&path).is_ok(),
811 "Path contains illegal characters: {:?}",
812 path
813 );
814 NamedPath { system, path }
815 }
816
817 pub fn path_ref(&self) -> &[String] {
819 &self.path
820 }
821
822 pub fn clone_path(&self) -> Vec<String> {
824 self.path.clone()
825 }
826
827 pub fn into_path(self) -> Vec<String> {
829 self.path
830 }
831
832 pub fn system_mut(&mut self) -> &mut SystemPath {
834 &mut self.system
835 }
836
837 pub fn push(&mut self, segment: String) -> Result<(), PathParseError> {
839 if let Some(last_segment) = self.path.last() {
840 validate_lookup_path_segment(last_segment, false)?;
841 }
842 validate_lookup_path_segment(&segment, true)?;
843 self.path.push(segment);
844 Ok(())
845 }
846
847 pub fn append(mut self, path: &str) -> Result<Self, PathParseError> {
849 if let Some(last_segment) = self.path.last() {
850 validate_lookup_path_segment(last_segment, false)?;
851 }
852 let mut segments = parse_path(path);
853 self.path.append(&mut segments);
854 validate_lookup_path(&self.path)?;
855 Ok(self)
856 }
857}
858
859impl SystemField for NamedPath {
860 fn system(&self) -> &SystemPath {
861 &self.system
862 }
863}
864
865impl TryFrom<String> for NamedPath {
866 type Error = PathParseError;
867
868 fn try_from(s: String) -> Result<Self, Self::Error> {
869 NamedPath::from_str(&s)
870 }
871}
872
873impl FromStr for NamedPath {
874 type Err = PathParseError;
875
876 fn from_str(s: &str) -> Result<Self, Self::Err> {
877 let s1: Vec<&str> = s.split("://").collect();
878 if s1.len() != 2 {
879 return Err(PathParseError::Form(s.to_string()));
880 }
881 let proto: Transport = s1[0].parse()?;
882 let mut s2: Vec<&str> = s1[1].split(PATH_SEP).collect();
883 if s2.is_empty() {
884 return Err(PathParseError::Form(s.to_string()));
885 }
886 let socket = SocketAddr::from_str(s2[0])?;
887 let path: Vec<String> = if s2.len() > 1 {
888 s2.split_off(1).into_iter().map(|v| v.to_string()).collect()
889 } else {
890 Vec::default()
891 };
892 validate_lookup_path(&path)?;
893 Ok(NamedPath::with_socket(proto, socket, path))
894 }
895}
896
897impl Div<&str> for NamedPath {
902 type Output = Self;
903
904 fn div(self, rhs: &str) -> Self::Output {
905 self.append(rhs).expect("illegal path")
906 }
907}
908impl Div<char> for NamedPath {
913 type Output = Self;
914
915 fn div(mut self, rhs: char) -> Self::Output {
916 self.push(rhs.to_string()).expect("illegal path");
917 self
918 }
919}
920
921pub fn parse_path(s: &str) -> Vec<String> {
923 s.split(PATH_SEP).map(|v| v.to_string()).collect()
924}
925
926pub fn validate_lookup_path(path: &[String]) -> Result<(), PathParseError> {
934 let len = path.len();
935 for (index, segment) in path.iter().enumerate() {
936 validate_lookup_path_segment(segment, (index + 1) == len)?;
937 }
938 Ok(())
939}
940
941pub fn validate_insert_path(path: &[String]) -> Result<(), PathParseError> {
949 for segment in path.iter() {
950 validate_insert_path_segment(segment)?;
951 }
952 Ok(())
953}
954
955pub(crate) fn validate_lookup_path_segment(
956 segment: &str,
957 is_last: bool,
958) -> Result<(), PathParseError> {
959 if segment.is_empty() {
960 return Err(PathParseError::Form(
961 "Path segments may not be empty!".to_string(),
962 ));
963 }
964 let len = segment.len();
965 for c in segment.chars() {
966 match c {
967 PATH_SEP => return Err(PathParseError::IllegalCharacter(PATH_SEP)),
968 BROADCAST_MARKER if !is_last && len == 1 => {
969 return Err(PathParseError::IllegalCharacter(BROADCAST_MARKER))
970 }
971 SELECT_MARKER if !is_last && len == 1 => {
972 return Err(PathParseError::IllegalCharacter(SELECT_MARKER))
973 }
974 UNIQUE_PATH_SEP => return Err(PathParseError::IllegalCharacter(UNIQUE_PATH_SEP)),
975 _ => (), }
977 }
978 Ok(())
979}
980pub(crate) fn validate_insert_path_segment(segment: &str) -> Result<(), PathParseError> {
981 if segment.is_empty() {
982 return Err(PathParseError::Form(
983 "Path segments may not be empty!".to_string(),
984 ));
985 }
986 for c in segment.chars() {
987 match c {
988 PATH_SEP => return Err(PathParseError::IllegalCharacter(PATH_SEP)),
989 BROADCAST_MARKER => return Err(PathParseError::IllegalCharacter(BROADCAST_MARKER)),
990 SELECT_MARKER => return Err(PathParseError::IllegalCharacter(SELECT_MARKER)),
991 UNIQUE_PATH_SEP => return Err(PathParseError::IllegalCharacter(UNIQUE_PATH_SEP)),
992 _ => (), }
994 }
995 Ok(())
996}
997
998#[cfg(test)]
999mod tests {
1000 use super::*;
1001
1002 const PATH: &str = "local://127.0.0.1:0/test_actor";
1003
1004 #[test]
1005 fn actor_path_strings() {
1006 let ap = ActorPath::from_str(PATH).expect("a proper path");
1007 println!("Got ActorPath={}", ap);
1008
1009 let s = ap.to_string();
1010 assert_eq!(PATH, &s);
1011 let ap2: ActorPath = s.parse().expect("a proper path");
1012 assert_eq!(ap, ap2);
1013 }
1014
1015 #[test]
1016 fn actor_path_unique_strings() {
1017 let ref1 = ActorPath::Unique(UniquePath::new(
1018 Transport::Local,
1019 "127.0.0.1".parse().expect("hardcoded IP"),
1020 8080,
1021 Uuid::new_v4(),
1022 ));
1023 let ref1_string = ref1.to_string();
1024 let ref1_deser = ActorPath::from_str(&ref1_string).expect("a proper path");
1025 let ref1_deser2: ActorPath = ref1_string.parse().expect("a proper path");
1026 assert_eq!(ref1, ref1_deser);
1027 assert_eq!(ref1, ref1_deser2);
1028 }
1029
1030 #[test]
1031 fn actor_path_named_strings() {
1032 let ref1 = ActorPath::Named(NamedPath::new(
1033 Transport::Local,
1034 "127.0.0.1".parse().expect("hardcoded IP"),
1035 8080,
1036 vec!["test".to_string(), "path".to_string()],
1037 ));
1038 let ref1_string = ref1.to_string();
1039 let ref1_deser = ActorPath::from_str(&ref1_string).expect("a proper path");
1040 let ref1_deser2: ActorPath = ref1_string.parse().expect("a proper path");
1041 assert_eq!(ref1, ref1_deser);
1042 assert_eq!(ref1, ref1_deser2);
1043 }
1044}