@@ -159,18 +159,17 @@ impl Registry {
159159 ) -> Result < ( Protocol < ' a > , & ' a [ u8 ] ) > {
160160 let n_input = input;
161161 let id_res = unsigned_varint:: decode:: u32 ( n_input) ;
162- if let Ok ( ( id, _rest) ) = id_res {
163- if !self . by_code . contains_key ( & id) {
164- return Err ( Error :: UnknownProtocolId ( id) ) ;
165- }
166- }
167162
168163 if let Ok ( res) = Protocol :: from_bytes ( input) {
169- return Ok ( res) ;
164+ let is_unknown = match & res. 0 {
165+ Protocol :: Unknown ( _, _) => true ,
166+ _ => false ,
167+ } ;
168+ if !is_unknown {
169+ return Ok ( res) ;
170+ }
170171 }
171172
172- let n_input = input;
173- let id_res = unsigned_varint:: decode:: u32 ( n_input) ;
174173 if let Ok ( ( id, rest) ) = id_res {
175174 if let Some ( def) = self . get_by_code ( id) {
176175 let ( data, out_rest) = if def. size == 0 {
@@ -193,6 +192,11 @@ impl Registry {
193192 } ;
194193 return Ok ( ( Protocol :: Custom { def, data } , out_rest) ) ;
195194 }
195+
196+ return Ok ( (
197+ Protocol :: Unknown ( id, std:: borrow:: Cow :: Borrowed ( rest) ) ,
198+ [ ] . as_ref ( ) ,
199+ ) ) ;
196200 }
197201
198202 Err ( Error :: UnknownProtocolId (
@@ -279,6 +283,15 @@ impl Registry {
279283 }
280284 Ok ( addr)
281285 }
286+
287+ /// Format a Multiaddr into a string using this registry
288+ pub fn to_string ( & self , addr : & Multiaddr ) -> String {
289+ let mut s = String :: new ( ) ;
290+ for p in self . iter ( addr) {
291+ s. push_str ( & p. to_string ( ) ) ;
292+ }
293+ s
294+ }
282295}
283296
284297#[ cfg( test) ]
@@ -356,8 +369,47 @@ mod tests {
356369 // Assert tcp fails now
357370 assert ! ( registry. try_from_str( "/ip4/127.0.0.1/tcp/80" ) . is_err( ) ) ;
358371
359- // And similarly from bytes
372+ // And similarly from bytes, it will now parse as Tcp since we natively fallback to standard protocols
360373 let vec = addr. to_vec ( ) ;
361- assert ! ( registry. try_from_bytes( & vec) . is_err( ) ) ;
374+ let parsed_unknown = registry. try_from_bytes ( & vec) . unwrap ( ) ;
375+ let mut parsed_iter = registry. iter ( & parsed_unknown) ;
376+ assert ! ( matches!( parsed_iter. next( ) , Some ( Protocol :: Ip4 ( _) ) ) ) ;
377+ assert ! ( matches!( parsed_iter. next( ) , Some ( Protocol :: Tcp ( 80 ) ) ) ) ;
378+ }
379+
380+ #[ test]
381+ fn test_custom_protocol_registry_printing ( ) {
382+ let mut registry = Registry :: new ( ) ;
383+ registry. register ( CustomProtocolDef {
384+ name : "my-custom" ,
385+ code : 999 ,
386+ size : -1 ,
387+ path : false ,
388+ transcoder : Some ( Box :: new ( SimpleTranscoder ) ) ,
389+ } ) ;
390+
391+ // Parsed string multi addr with a custom protocol
392+ let addr = registry
393+ . try_from_str ( "/ip4/127.0.0.1/my-custom/helloworld" )
394+ . unwrap ( ) ;
395+
396+ // 1. Printing with Registry works as expected, displaying the registered custom format
397+ let registry_printed = registry. to_string ( & addr) ;
398+ assert_eq ! ( registry_printed, "/ip4/127.0.0.1/my-custom/helloworld" ) ;
399+
400+ // 2. Native Multiaddr printing gracefully falls back to unknown without panicking
401+ let native_printed = addr. to_string ( ) ;
402+ // Native printing uses base58 for the rest of the bytes (the length varint and data).
403+ // For size=-1, the length varint `10` followed by "helloworld" becomes '3ah4EQvnau95Y8K'
404+ assert_eq ! ( native_printed, "/ip4/127.0.0.1/unknown-999/3ah4EQvnau95Y8K" ) ;
405+
406+ // 3. Confirm that the final 'unknown-999' round-trips on parse back to the same multiaddr
407+ let parsed_back = native_printed
408+ . parse :: < Multiaddr > ( )
409+ . expect ( "Should parse unknown protocol formatting natively" ) ;
410+ assert_eq ! (
411+ parsed_back, addr,
412+ "Round-trip multiaddr bytes must match the original instance precisely"
413+ ) ;
362414 }
363415}
0 commit comments