I've been trying to wrtite a structure that finds TopN elemements in a collection:
pub struct TopN<const N: usize, Item, Key, KeyFn>
where
Key: Ord,
KeyFn: FnMut(&Item) -> Key,
{
// Keeps top-n items, sorted descending
array: SmallVec<[Item; N]>,
key: KeyFn,
}
The general case is easy - it takes a function from outside, so the compiler can figure out the Key
and KeyFn
types:
impl<const N: usize, Item, Key, KeyFn> TopN<N, Item, Key, KeyFn>
where
Key: Ord,
KeyFn: FnMut(&Item) -> Key,
{
pub fn by_key(f: KeyFn) -> TopN<N, Item, Key, KeyFn> {
TopN {
array: SmallVec::new(),
key: f,
}
}
...
But then I'd like to also make it work for a special case, where the function is just identity, so I'd like to have a special constructor new()
that doesn't take a function:
type IdentityFn<T> = fn(&T) -> T;
pub fn identity<T: Copy>(item: &T) -> T {
*item
}
impl<const N: usize, Item> TopN<N, Item, Item, IdentityFn<Item>>
where
Item: Ord + Copy,
{
pub fn new() -> TopN<N, Item, Item, IdentityFn<Item>> {
TopN {
array: SmallVec::new(),
key: identity::<Item>,
}
}
}
This compiles and works, but runs into a performance problem, because now it takes a pointer to a function. But I'd like to specialize it for my concrete identity
function. How do I do that?
I guess I need sth like:
type IdentityFn<T> = concrete_type_of(identity::<T>);
Is it possible?