Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 26 additions & 3 deletions iroh-relay/src/relay_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,11 +112,34 @@ impl RelayMap {
self.relays.write().expect("poisoned").remove(url)
}

/// Joins this `RelayMap` with another one into a new one
pub fn join(self, other: RelayMap) -> RelayMap {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't this called chain usually? I think this is very similar to the Iterator::chain signature.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes it is. I opted for join because a Map is not something that can (semantically) be put into a ⛓️ chain! 😉 I think of chain() something that can be applied to a sequence of something (hence Iterator::chain but not BTreeMap::chain for example).

I have no strong feelings about the actual method name tho, so if you want me to change it, I'll happily do so.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not convinced passing owned versions makes sense for a fully clonable thing. This API really doesn't communicate the fact that this doesn't actually create a new version, but rather modifies the underlying, likely shared instances

{
let mut a = self.relays.write().expect("poisoned");
let b = other.relays.read().expect("poisoned");
a.extend(b.iter().map(|(a, b)| (a.clone(), b.clone())));
}
self
}
}

impl Extend<(RelayUrl, Arc<RelayConfig>)> for RelayMap {
/// Extends this `RelayMap` with another one.
pub fn extend(&self, other: &RelayMap) {
///
/// You can use this like this:
///
/// ```rust
/// # let relay_map_a: RelayMap = { unimplemented!() };
/// # let relay_map_b: RelayMap = { unimplemented!() };
///
/// relay_map_a.extend(relay_map_b.relays::<Vec<_>>());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is less efficient, and seems rather pointless to support, if you have to collect & allocate into a vector first before using the trait

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The inner lock seems to stop you from doing anything nice using IntoIterator or Extend. 😞

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, that's the issue yes.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this would be a DashMap, I guess it would work.

That also would mean that not the whole map must be locked when adding/removing.

But it introduces other things that are dangerous, such as holding dashmap locks over await points (which can be linted against though).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How do you lint against that? I didn't know that was possible.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But clippy can do that (by now) via the await-holding-invalid-types lint: https://rust-lang.github.io/rust-clippy/stable/index.html#await_holding_invalid_type

/// ```
fn extend<I>(&mut self, iter: I)
where
I: IntoIterator<Item = (RelayUrl, Arc<RelayConfig>)>,
{
let mut a = self.relays.write().expect("poisoned");
let b = other.relays.read().expect("poisoned");
a.extend(b.iter().map(|(a, b)| (a.clone(), b.clone())));
a.extend(iter);
}
}

Expand Down
Loading