From bf43fabf65fe4062f582e59fe21e92a0b0f48cb8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bla=C5=BE=20Hrastnik?= <blaz@mxxn.io>
Date: Mon, 19 Jul 2021 11:19:05 +0900
Subject: [PATCH] Remove ExactSizeIterator requirement on Transaction::change

Size hint is enough.
---
 helix-core/src/diff.rs        | 56 +++++++++++++++++------------------
 helix-core/src/transaction.rs |  6 ++--
 2 files changed, 31 insertions(+), 31 deletions(-)

diff --git a/helix-core/src/diff.rs b/helix-core/src/diff.rs
index 9c1fc999..a83db333 100644
--- a/helix-core/src/diff.rs
+++ b/helix-core/src/diff.rs
@@ -1,6 +1,4 @@
-use ropey::Rope;
-
-use crate::{Change, Transaction};
+use crate::{Rope, Transaction};
 
 /// Compares `old` and `new` to generate a [`Transaction`] describing
 /// the steps required to get from `old` to `new`.
@@ -25,34 +23,34 @@ pub fn compare_ropes(old: &Rope, new: &Rope) -> Transaction {
     // The current position of the change needs to be tracked to
     // construct the `Change`s.
     let mut pos = 0;
-    let changes: Vec<Change> = diff
-        .ops()
-        .iter()
-        .map(|op| op.as_tag_tuple())
-        .filter_map(|(tag, old_range, new_range)| {
-            // `old_pos..pos` is equivalent to `start..end` for where
-            // the change should be applied.
-            let old_pos = pos;
-            pos += old_range.end - old_range.start;
+    Transaction::change(
+        old,
+        diff.ops()
+            .iter()
+            .map(|op| op.as_tag_tuple())
+            .filter_map(|(tag, old_range, new_range)| {
+                // `old_pos..pos` is equivalent to `start..end` for where
+                // the change should be applied.
+                let old_pos = pos;
+                pos += old_range.end - old_range.start;
 
-            match tag {
-                // Semantically, inserts and replacements are the same thing.
-                similar::DiffTag::Insert | similar::DiffTag::Replace => {
-                    // This is the text from the `new` rope that should be
-                    // inserted into `old`.
-                    let text: &str = {
-                        let start = new.char_to_byte(new_range.start);
-                        let end = new.char_to_byte(new_range.end);
-                        &new_converted[start..end]
-                    };
-                    Some((old_pos, pos, Some(text.into())))
+                match tag {
+                    // Semantically, inserts and replacements are the same thing.
+                    similar::DiffTag::Insert | similar::DiffTag::Replace => {
+                        // This is the text from the `new` rope that should be
+                        // inserted into `old`.
+                        let text: &str = {
+                            let start = new.char_to_byte(new_range.start);
+                            let end = new.char_to_byte(new_range.end);
+                            &new_converted[start..end]
+                        };
+                        Some((old_pos, pos, Some(text.into())))
+                    }
+                    similar::DiffTag::Delete => Some((old_pos, pos, None)),
+                    similar::DiffTag::Equal => None,
                 }
-                similar::DiffTag::Delete => Some((old_pos, pos, None)),
-                similar::DiffTag::Equal => None,
-            }
-        })
-        .collect();
-    Transaction::change(old, changes.into_iter())
+            }),
+    )
 }
 
 #[cfg(test)]
diff --git a/helix-core/src/transaction.rs b/helix-core/src/transaction.rs
index 048839b3..e20e550f 100644
--- a/helix-core/src/transaction.rs
+++ b/helix-core/src/transaction.rs
@@ -473,11 +473,13 @@ impl Transaction {
     /// Generate a transaction from a set of changes.
     pub fn change<I>(doc: &Rope, changes: I) -> Self
     where
-        I: IntoIterator<Item = Change> + ExactSizeIterator,
+        I: IntoIterator<Item = Change> + Iterator,
     {
         let len = doc.len_chars();
 
-        let mut changeset = ChangeSet::with_capacity(2 * changes.len() + 1); // rough estimate
+        let (lower, upper) = changes.size_hint();
+        let size = upper.unwrap_or(lower);
+        let mut changeset = ChangeSet::with_capacity(2 * size + 1); // rough estimate
 
         // TODO: verify ranges are ordered and not overlapping or change will panic.