{"action":"created","issue":{"url":"https://api.github.com/repos/bluss/rust-itertools/issues/88","labels_url":"https://api.github.com/repos/bluss/rust-itertools/issues/88/labels{/name}","comments_url":"https://api.github.com/repos/bluss/rust-itertools/issues/88/comments","events_url":"https://api.github.com/repos/bluss/rust-itertools/issues/88/events","html_url":"https://github.com/bluss/rust-itertools/pull/88","id":124650411,"number":88,"title":"Added `diff.rs` module with `diff` and `copy_on_diff` - for efficiently \"diff\"ing and caching non-`Clone` iterators.","user":{"login":"mitchmindtree","id":4587373,"avatar_url":"https://avatars.githubusercontent.com/u/4587373?v=3","gravatar_id":"","url":"https://api.github.com/users/mitchmindtree","html_url":"https://github.com/mitchmindtree","followers_url":"https://api.github.com/users/mitchmindtree/followers","following_url":"https://api.github.com/users/mitchmindtree/following{/other_user}","gists_url":"https://api.github.com/users/mitchmindtree/gists{/gist_id}","starred_url":"https://api.github.com/users/mitchmindtree/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mitchmindtree/subscriptions","organizations_url":"https://api.github.com/users/mitchmindtree/orgs","repos_url":"https://api.github.com/users/mitchmindtree/repos","events_url":"https://api.github.com/users/mitchmindtree/events{/privacy}","received_events_url":"https://api.github.com/users/mitchmindtree/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":{"login":"bluss","id":3209739,"avatar_url":"https://avatars.githubusercontent.com/u/3209739?v=3","gravatar_id":"","url":"https://api.github.com/users/bluss","html_url":"https://github.com/bluss","followers_url":"https://api.github.com/users/bluss/followers","following_url":"https://api.github.com/users/bluss/following{/other_user}","gists_url":"https://api.github.com/users/bluss/gists{/gist_id}","starred_url":"https://api.github.com/users/bluss/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/bluss/subscriptions","organizations_url":"https://api.github.com/users/bluss/orgs","repos_url":"https://api.github.com/users/bluss/repos","events_url":"https://api.github.com/users/bluss/events{/privacy}","received_events_url":"https://api.github.com/users/bluss/received_events","type":"User","site_admin":false},"milestone":null,"comments":14,"created_at":"2016-01-03T14:12:19Z","updated_at":"2016-01-21T00:51:49Z","closed_at":null,"pull_request":{"url":"https://api.github.com/repos/bluss/rust-itertools/pulls/88","html_url":"https://github.com/bluss/rust-itertools/pull/88","diff_url":"https://github.com/bluss/rust-itertools/pull/88.diff","patch_url":"https://github.com/bluss/rust-itertools/pull/88.patch"},"body":"I originally wrote this module for a couple of cases in conrod where I wanted to cache a non-`Clone` iterator without having to collect the iterator into a `Vec` for comparison in case the cache needed updating.\r\n\r\nI've just come across another similar case in a personal project, so before copying code across I thought I'd approach the itertools team in case you deem it worthy of adding to your luscious collection.\r\n\r\nEither way, any feedback appreciated!"},"comment":{"url":"https://api.github.com/repos/bluss/rust-itertools/issues/comments/173415581","html_url":"https://github.com/bluss/rust-itertools/pull/88#issuecomment-173415581","issue_url":"https://api.github.com/repos/bluss/rust-itertools/issues/88","id":173415581,"user":{"login":"bluss","id":3209739,"avatar_url":"https://avatars.githubusercontent.com/u/3209739?v=3","gravatar_id":"","url":"https://api.github.com/users/bluss","html_url":"https://github.com/bluss","followers_url":"https://api.github.com/users/bluss/followers","following_url":"https://api.github.com/users/bluss/following{/other_user}","gists_url":"https://api.github.com/users/bluss/gists{/gist_id}","starred_url":"https://api.github.com/users/bluss/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/bluss/subscriptions","organizations_url":"https://api.github.com/users/bluss/orgs","repos_url":"https://api.github.com/users/bluss/repos","events_url":"https://api.github.com/users/bluss/events{/privacy}","received_events_url":"https://api.github.com/users/bluss/received_events","type":"User","site_admin":false},"created_at":"2016-01-21T00:51:49Z","updated_at":"2016-01-21T00:51:49Z","body":"Great. What pains me is how much more efficient it is to write copy_on_diff specifically for slices and vecs rather than iterators. I haven't profiled it, but it's my general understanding. Slice version below. It could be even a bit better with more detailed preallocation of the vector.\r\n\r\n```rust\r\npub fn copy_on_diff<'a, U, T: 'a>(collection: &'a [T], update: U) -> Cow<'a, [T]>\r\n    where U: IntoIterator<Item=T>,\r\n          T: Clone + PartialEq,\r\n{\r\n    let c_iter = collection.into_iter();\r\n    match diff_by_ref(collection.into_iter(), update.into_iter()) {\r\n        Some(diff) => match diff {\r\n            Diff::FirstMismatch(idx, _, mismatch) => {\r\n                let mut v = collection[..idx].to_vec();\r\n                let (top, rest) = mismatch.into_parts();\r\n                if let Some(elt) = top {\r\n                    v.push(elt);\r\n                }\r\n                v.extend(rest);\r\n                Cow::Owned(v)\r\n            }\r\n            Diff::Longer(_, remaining) => {\r\n                let mut v = collection.to_vec();\r\n                let (top, rest) = remaining.into_parts();\r\n                if let Some(elt) = top {\r\n                    v.push(elt);\r\n                }\r\n                v.extend(rest);\r\n                Cow::Owned(v)\r\n            }\r\n            Diff::Shorter(num_update, _) => {\r\n                Cow::Owned(collection[..num_update].to_vec())\r\n            }\r\n        },\r\n        None => Cow::Borrowed(collection),\r\n    }\r\n}\r\n```"}}