2

For my project I want to collect some data, where the order in which the data is added should be maintained. BTreeMap does sort it's keys and HashMap warns that the keys are in no particular order.

So I created another Map type:

/// Map implementation that keeps the keys in the order at which they are created.
///
/// ```rust
/// # use d3rs::data_collections::SequenceMap;
///
/// let map = SequenceMap::from([("B", 102), ("D", 204), ("D", 301), ("B", 403)]);
/// let mut iter = map.iter();
/// assert_eq!(iter.next(), Some((&"B", &403)));
/// assert_eq!(iter.next(), Some((&"D", &301)));
/// assert_eq!(iter.next(), None);
/// ```
#[derive(Debug, Default)]
pub struct SequenceMap<K, V> {
    data: HashMap<K, V>,
    sequence: Vec<K>,
}

impl<K, V> SequenceMap<K, V>
where
    K: Display + Hash + Eq,
{
pub fn new() -> Self {
        Self {
            data: HashMap::new(),
            sequence: Vec::new(),
        }
    }

    pub fn insert(&mut self, key: K, value: V) -> Option<V>
    where
        K: Copy,
    {
        let result = self.data.insert(key, value);

        if result.is_none() {
            self.sequence.push(key);
        }

        result
    }

   // some other methods skipped
}

The trait bounds for K are similar to those for HashMap, but for the implementation of the insert method a subtle addition is required: Copy.

Now, one of the great things about HashMap is that you can use any key type (as long as it has Hash + Eq, which are derivable). This means that even String and user defined types can be used as the key, where the various iterators and the get method get a borrow to the key type as an argument.

In order to have the keys returned in the order in which they were defined, I use an internal Vector to hold the keys in that order. This is why the Copy trait is now required for the Key type, otherwise the borrow checker wouldn't allow the push after the insert.

But this makes it cumbersome to have Strings and user defined types as the keys, since they should now also implement Copy (which is a potentially time-consuming process)

How could I remove the Copy restriction?

Herohtar
  • 5,347
  • 4
  • 31
  • 41

1 Answers1

2

You can use Clone instead of Copy, and it will allow you to use types like String that implements Clone but not Copy. See What is the difference between Copy and Clone?.

But you'll not be able to accept any type, because there is an important difference between your implementation and HashMap's: you save the values in a Vec, in addition to inside the map. So your values must have some way to be duplicated, because they are duplicated.

If possible, you can use a reference counting pointer like Rc, but it'll prevent mutation.

Chayim Friedman
  • 47,971
  • 5
  • 48
  • 77
  • Clone was what I wanted to prevent, but you are right that the implementation does require a clone of the Key in the Vector. I'll go for the IndexMap suggestion of @Caesar – Harry de Kroon Apr 13 '22 at 14:13