radicle: Keep pinned repos ordered in config
A trivial patch suggested by @Johannes in zulip:
Do not return them in a random order in radicle-httpd, so that we can have them in a defined order in radicle-explorer.
A trivial patch suggested by @Johannes in zulip:
Do not return them in a random order in radicle-httpd, so that we can have them in a defined order in radicle-explorer.
Thanks for the contribution! Changing from a HashSet to a Vec doesn’t preserve uniqueness of the repositories, so I think this change would be more involved. I started sketching a better interface for that:
/// Pin a repository at a given position.
///
/// See [`Pinned::pin`].
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct PinAt {
rid: RepoId,
index: usize,
}
impl PinAt {
/// Construct a new `PinAt` given a [`RepoId`] to pin, and the `index` it is
/// expected to be pinned at.
pub fn new(rid: RepoId, at: usize) -> Self {
Self { rid, index: at }
}
}
impl Pinned {
/// Create a new set of [`Pinned`] repositories.
pub fn new() -> Self {
Self {
repositories: Vec::new(),
}
}
/// Return all the pinned [`RepoId`]s.
pub fn repositories(&self) -> impl Iterator<Item = &RepoId> {
self.repositories.iter()
}
/// Return all the pinned [`RepoId`]s, alongside their index.
pub fn indexed_repositories(&self) -> impl Iterator<Item = PinAt> + use<'_> {
self.repositories
.iter()
.enumerate()
.map(|(index, rid)| PinAt { rid: *rid, index })
}
/// Pin a repository using a given index. Note that if the index is out of
/// bounds, then the [`RepoId`] is inserted at the end of the list.
///
/// Ensures that the [`RepoId`] is unique.
pub fn pin_at(&mut self, pin_at: PinAt) {
if !self.is_pinned(&pin_at.rid) {
let PinAt { rid, index } = pin_at;
// SAFETY: the use of `min` ensures that the `index < len` for the call
// to `insert`.
self.repositories
.insert(index.min(self.repositories.len()), rid);
}
}
/// Pin a repository, by inserting it at the end of the set of repositories.
///
/// Ensures that the [`RepoId`] is unique.
pub fn pin(&mut self, rid: RepoId) {
if !self.is_pinned(&rid) {
self.repositories.push(rid);
}
}
/// Unpin a repository.
pub fn unpin(&mut self, rid: &RepoId) {
self.repositories.retain(|rid_| rid_ != rid);
}
/// Checks if the given [`RepoId`] is in the set of pinned repositories.
pub fn is_pinned(&self, rid: &RepoId) -> bool {
self.repositories.contains(rid)
}
}
However, I’m still figuring out a nice way to ensure that Serialize and Deserialize ensure this uniqueness property.
Superseded by patch f0c87afd0186a2931ae2c67b7ab026ddc931bfbf