Skip to content

Commit d0e9ec2

Browse files
feat: add with_p2p method (#102)
1 parent d9108c9 commit d0e9ec2

File tree

3 files changed

+83
-0
lines changed

3 files changed

+83
-0
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
# 0.18.1 - unreleased
2+
3+
- Add `with_p2p` on `Multiaddr`. See [PR 102].
4+
5+
[PR 102]: https://github.com/multiformats/rust-multiaddr/pull/102
6+
17
# 0.18.0
28

39
- Add `WebTransport` instance for `Multiaddr`. See [PR 70].

src/lib.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ use std::{
2626
sync::Arc,
2727
};
2828

29+
use libp2p_identity::PeerId;
30+
2931
#[cfg(feature = "url")]
3032
pub use self::from_url::{from_url, from_url_lossy, FromUrlErr};
3133

@@ -127,6 +129,18 @@ impl Multiaddr {
127129
self
128130
}
129131

132+
/// Appends the given [`PeerId`] if not yet present at the end of this multiaddress.
133+
///
134+
/// Fails if this address ends in a _different_ [`PeerId`].
135+
/// In that case, the original, unmodified address is returned.
136+
pub fn with_p2p(self, peer: PeerId) -> std::result::Result<Self, Self> {
137+
match self.iter().last() {
138+
Some(Protocol::P2p(p)) if p == peer => Ok(self),
139+
Some(Protocol::P2p(_)) => Err(self),
140+
_ => Ok(self.with(Protocol::P2p(peer))),
141+
}
142+
}
143+
130144
/// Returns the components of this multiaddress.
131145
///
132146
/// # Example

tests/lib.rs

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -661,3 +661,66 @@ fn arbitrary_impl_for_all_proto_variants() {
661661
let variants = core::mem::variant_count::<Protocol>() as u8;
662662
assert_eq!(variants, Proto::IMPL_VARIANT_COUNT);
663663
}
664+
665+
mod multiaddr_with_p2p {
666+
use libp2p_identity::PeerId;
667+
use multiaddr::Multiaddr;
668+
669+
fn test_multiaddr_with_p2p(
670+
multiaddr: &str,
671+
peer: &str,
672+
expected: std::result::Result<&str, &str>,
673+
) {
674+
let peer = peer.parse::<PeerId>().unwrap();
675+
let expected = expected
676+
.map(|a| a.parse::<Multiaddr>().unwrap())
677+
.map_err(|a| a.parse::<Multiaddr>().unwrap());
678+
679+
let mut multiaddr = multiaddr.parse::<Multiaddr>().unwrap();
680+
// Testing multiple time to validate idempotence.
681+
for _ in 0..3 {
682+
let result = multiaddr.with_p2p(peer);
683+
assert_eq!(result, expected);
684+
multiaddr = result.unwrap_or_else(|addr| addr);
685+
}
686+
}
687+
688+
#[test]
689+
fn empty_multiaddr() {
690+
// Multiaddr is empty -> it should push and return Ok.
691+
test_multiaddr_with_p2p(
692+
"",
693+
"QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN",
694+
Ok("/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN"),
695+
)
696+
}
697+
#[test]
698+
fn non_p2p_terminated() {
699+
// Last protocol is not p2p -> it should push and return Ok.
700+
test_multiaddr_with_p2p(
701+
"/ip4/127.0.0.1",
702+
"QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN",
703+
Ok("/ip4/127.0.0.1/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN"),
704+
)
705+
}
706+
707+
#[test]
708+
fn p2p_terminated_same_peer() {
709+
// Last protocol is p2p and the contained peer matches the provided one -> it should do nothing and return Ok.
710+
test_multiaddr_with_p2p(
711+
"/ip4/127.0.0.1/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN",
712+
"QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN",
713+
Ok("/ip4/127.0.0.1/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN"),
714+
)
715+
}
716+
717+
#[test]
718+
fn p2p_terminated_different_peer() {
719+
// Last protocol is p2p but the contained peer does not match the provided one -> it should do nothing and return Err.
720+
test_multiaddr_with_p2p(
721+
"/ip4/127.0.0.1/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN",
722+
"QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC",
723+
Err("/ip4/127.0.0.1/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN"),
724+
)
725+
}
726+
}

0 commit comments

Comments
 (0)