indexmap-rs / indexmap

A hash table with consistent order and fast iteration; access items by key or sequence index
https://docs.rs/indexmap/
Other
1.67k stars 150 forks source link

Feature request: `Into<std::collections::HashMap>` #345

Open SamuelMarks opened 1 week ago

SamuelMarks commented 1 week ago

Many third party crates require the OG.

Sure I can do this:

let mut hm = std::collections::HashMap::<String, String>::with_capacity(env.len());
for (k,v) in env.iter() {
    hm.insert(k.to_owned(), v.to_owned());
}

But it's not as ergonomic as an Into or From.

cuviper commented 1 week ago

For Copy-able key-values (less general than ToOwned), you could change your example to:

let mut hm = std::collections::HashMap::<String, String>::with_capacity(env.len());
hm.extend(env.iter()); // using `Extend<(&K, &V)>`

(edit: I wrote Clone-able at first, but that Extend requires Copy. So this doesn't apply to your String key-values.)

I would expect Into to pass ownership though, in which case you can simply write HashMap::from_iter(env). When using the conversion in an inferrable context, you can write foo(env.into_iter().collect()). Either way, this involves a bit of complexity in rehashing everything, so I don't think it should be hidden behind Into.

However, if raw_entry_mut ever stabilizes, we could possibly do better for conversions that keep the same underlying hasher, because IndexMap also caches the hash values in its internal Bucket. Something like:

impl<K, V, S> From<IndexMap<K, V, S>> for HashMap<K, V, S>
where
    K: Eq + Hash,
    S: BuildHasher,
{
    fn from(imap: IndexMap<K, V, S>) -> Self {
        let mut hmap = HashMap::with_capacity_and_hasher(imap.len(), imap.hash_builder);
        for bucket in imap.core.into_entries() {
            hmap
                .raw_entry_mut()
                .from_key_hashed_nocheck(bucket.hash.get(), &bucket.key)
                .or_insert(bucket.key, bucket.value);
        }
        hmap
    }
}

In theory, IndexSet to HashSet could do the same, but there's no such raw API at all yet.