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 
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,
{
// ......
}
impl <K: Hash + std::cmp::Eq, V, const C: usize> FixedSizeHashMap <K, V, C>
where
Guard<{
C <= 25013 /// << === Simple expression works
}>: Protect,
{