rust/hg-core/src/utils.rs
changeset 46653 a069639783a0
parent 46640 755c31a1caf9
child 46708 e8cd519a0a34
--- a/rust/hg-core/src/utils.rs	Thu Feb 25 23:14:35 2021 +0100
+++ b/rust/hg-core/src/utils.rs	Thu Feb 25 21:25:04 2021 +0100
@@ -11,6 +11,8 @@
 use crate::utils::hg_path::HgPath;
 use im_rc::ordmap::DiffItem;
 use im_rc::ordmap::OrdMap;
+use std::cell::Cell;
+use std::fmt;
 use std::{io::Write, ops::Deref};
 
 pub mod files;
@@ -378,3 +380,43 @@
         right
     }
 }
+
+/// Join items of the iterable with the given separator, similar to Python’s
+/// `separator.join(iter)`.
+///
+/// Formatting the return value consumes the iterator.
+/// Formatting it again will produce an empty string.
+pub fn join_display(
+    iter: impl IntoIterator<Item = impl fmt::Display>,
+    separator: impl fmt::Display,
+) -> impl fmt::Display {
+    JoinDisplay {
+        iter: Cell::new(Some(iter.into_iter())),
+        separator,
+    }
+}
+
+struct JoinDisplay<I, S> {
+    iter: Cell<Option<I>>,
+    separator: S,
+}
+
+impl<I, T, S> fmt::Display for JoinDisplay<I, S>
+where
+    I: Iterator<Item = T>,
+    T: fmt::Display,
+    S: fmt::Display,
+{
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        if let Some(mut iter) = self.iter.take() {
+            if let Some(first) = iter.next() {
+                first.fmt(f)?;
+            }
+            for value in iter {
+                self.separator.fmt(f)?;
+                value.fmt(f)?;
+            }
+        }
+        Ok(())
+    }
+}