Help with [E0599] when implementing trait

I am trying to implement a fixed size hash map with DoubleEndedIterator and Index traits in order to learn Rust concepts of traits, iterators, ownership etc. (p.s. it's toy code!!) and have a error I can't see to get around.

pub struct FixedSizeHashMap <K, V, const C: usize>  {
    _data: Vec<Option<Entry<K, V>>>,
    _size: usize,

   //... ommited .. code
}

#[guard(is_prime(C as u64))]
#[guard(C <= 25013)]
impl <K: Hash + std::cmp::Eq, V, const C: usize> FixedSizeHashMap <K, V, C>  {
    // ... ommited code ....
    pub fn get(&self, key: &K) -> Option<&V> {
        let i = self._find_index(&key);
        match self._get_at(i) {
            Some(key_val_pair) => Some(key_val_pair.1),
            None => None
        }
    }
    // ... omited code
}

impl <K: Hash + std::cmp::Eq, V, const C: usize> Index<&K> for FixedSizeHashMap <K, V, C> {
    type Output = V;
    fn index(&self, key: &K) -> &Self::Output {
        self.get(key).except("not found in map") //!!! <<= COMPILER ERROR HERE!!
    }
}

I get a compiler error in my fn index:

error[E0599]: no method named `get` found for reference `&hash_map::FixedSizeHashMap<K, V, C>` in the current scope
   --> libs/hash_map/src/hash_map.rs:220:14
    |
220 |         self.get(key).expect("Panic! not in map")
    |              ^^^
    |
    = help: items from traits can only be used if the trait is implemented and in scope
    = note: the following trait defines an item `get`, perhaps you need to implement it:
            candidate #1: `SliceIndex`
  • The get method is pub and works
  • I am able to access _data, _usize etc from impl Index block.
  • Similar situation for or there impl Iterator block as well.
  • My implementation is similar to std::HashMap so I think I'm doing something stupid.
  • It maybe something to do with ... candidate #1: ``SliceIndex`` and requires some where bound to be satisfied but I can't figure out.

Any help appreciated!!!

what are these #[guard(...)] attributes expanded into? does it compile if you remove these attributes?

it's from https://docs.rs/const_guards/latest/const_guards/

src: lib.rs - source

To ensure compile time check for C (capacity) and to ensure C is a prime number.

It works when I remove the #[guard...]. But of course I would like the static compiler checks (similar to std::static_assert and constexpr in C++)

looking at the documentation, the attributes are expanded into a complex where clause, that's why the get() method is not found: because the bounds in the where clause is not met!

either you remove the attributes, or you must repeat the #[guard(...)] attributes whenever you use it in generic context.

I tried to repeat the #[guard(...) attributes in all impl blocks (in my case only impl Index but same error :frowning:

I also tried to manually simulate what the macro seems to expand:

// ... omited code
impl <K: Hash + std::cmp::Eq, V, const C: usize> FixedSizeHashMap <K, V, C>
 where
    Guard<{
        const fn _f_guard<const C: usize>() -> bool {
            if !C <= 25013 {
                panic!("guard evaluated to false")
           }
            true
        }
        _f_guard::<C>()
    }>: Protect,
{
  // ommited
} 

impl <K: Hash + std::cmp::Eq, V, const C: usize> Index<&K> for FixedSizeHashMap <K, V, C>
 where
    Guard<{
        const fn _f_guard<const C: usize>() -> bool {
            if !C <= 25013 {
                panic!("guard evaluated to false")
           }
            true
        }
        _f_guard::<C>()
    }>: Protect,
{
  // same as above (ommited)
}

and still the same error :-(.

What baffles me is where is the dependency on SlicedIndex ... where does it come from? It seems weird as no part of my code or Index spec requires it.

so it seems the bounds of the synthetic where clause is the problem. maybe they are too complicated for the type checker.

try to restrict the scope of the #[guard(...)] attributes, e.g. putting it on the constructors (and algorithms that rely on them) should be enough.

it's just the compiler trying to be helpful using the method name as heuristics, it's unrelated to the compile error here.

I also tried these:

  • Doesn't work (same (E0599) error) .... somehow doesn't like the _f_guard funciton even though it just returns true:
struct Guard<const U: bool>;
trait Protect {}
impl Protect for Guard<true> {}

impl <K: Hash + std::cmp::Eq, V, const C: usize> Index<&K> for FixedSizeHashMap <K, V, C>
 where
    Guard<{
        const fn _f_guard<const C: usize>() -> bool {
            true
        }
        _f_guard::<C>()
    }>: Protect,
{
   // ......
}
  • Doesnt work => (error expression is too complex and suggest I use a const fn):
impl <K: Hash + std::cmp::Eq, V, const C: usize> Index<&K> for FixedSizeHashMap <K, V, C>
 where
    Guard<{
       if !C <= 25013 {
            panic!("guard evaluated to false")
         }
        true    // <<========== Error expression is too complex
    }>: Protect,
{
   // ......
}
  • Works!!! =>
impl <K: Hash + std::cmp::Eq, V, const C: usize> FixedSizeHashMap <K, V, C>
 where
    Guard<{
        C <= 25013  /// << === Simple expression works
    }>: Protect,
{