lakwet / voracious_sort

Voracious radix sort
MIT License
58 stars 1 forks source link

Any way to impl Radixable for a generic struct? #9

Open mcronce opened 2 years ago

mcronce commented 2 years ago

I'm looking to use voracious sort in a project with the following structs (modified to try to utilize voracious sort):

// DRY
trait Key: Copy + Eq + Hash + Ord + for<'de> Deserialize<'de> + Serialize + RadixKey {}
impl<T> Key for T where T: Copy + Eq + Hash + Ord + for<'de> Deserialize<'de> + Serialize + RadixKey {}

struct IndexEntry<K: Key> {
    key: K,
    position: u64
}

// Store is an on-disk key-value store w/ sorted index
struct Store<K: Key, T: Serialize + DeserializeOwned> {
    path: PathBuf,
    file: BufStream<File>,
    header: Header,
    index_cache: HashMap<K, u64>,
    _phantom: std::marker::PhantomData<T>
}

However, this impl Radixable fails, requiring Dispatcher:

impl<K: RadixKey> Radixable<K> for IndexEntry<K> {
    type Key = K;
    #[inline]
    fn key(&self) -> Self::Key {
        self.key
    }
}

The obvious solution is to add a Dispatcher bound on K:

trait Key: Copy + Eq+ Hash + Ord + for<'de> Deserialize<'de> + Serialize + RadixKey + Dispatcher<Self<K>, K> {}
impl<T> Key for T where T: Copy + Eq+ Hash + Ord + for<'de> Deserialize<'de> + Serialize + RadixKey + Dispatcher<T<K>, K> {}

- or -

// keep Key the same and add bounds directly on the structs
struct IndexEntry<K: Key + Dispatcher<IndexEntry<K>, K>> { /* ... */ }
struct Store<K: Key + Dispatcher<IndexEntry<K>, K>, T: Serialize + DeserializeOwned> { /* ... */ }

But this produces a compile error:

error[E0275]: overflow evaluating the requirement `u8: Dispatcher<IndexEntry<u8>, u8>`
   --> src/lib.rs:559:34
    |
559 |         let mut store: Store<u8, u8> = Store::new(path).await.unwrap();
    |                                        ^^^^^^^^^^
    |
note: required because of the requirements on the impl of `Radixable<u8>` for `IndexEntry<u8>`
   --> src/lib.rs:134:45
    |
134 | impl<K: Key + Dispatcher<IndexEntry<K>, K>> Radixable<K> for IndexEntry<K> {
    |                                             ^^^^^^^^^^^^     ^^^^^^^^^^^^^
    = note: required because of the requirements on the impl of `Dispatcher<IndexEntry<u8>, u8>` for `u8`
note: required by a bound in `Store::<K, T>::new`
   --> src/lib.rs:195:11
    |
195 |     K: Key + Dispatcher<IndexEntry<K>, K>,
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Store::<K, T>::new`
...
202 |     pub async fn new(path: impl AsRef<Path>) -> Result<Self, Error<K>> /* {{{ */ {
    |                  --- required by a bound in this

Alternatively, trying to add a blanket impl Dispatcher violates orphan rules:

impl<T> Dispatcher<IndexEntry<T>, T> for T where T: Key {}
error[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`IndexEntry<T>`)
   --> src/lib.rs:116:6
    |
116 | impl<T> Dispatcher<IndexEntry<T>, T> for T where T: Key {}
    |      ^ type parameter `T` must be covered by another type when it appears before the first local type (`IndexEntry<T>`)
    |
    = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type
    = note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last

I feel like I'm missing something that would be obvious to somebody who has more experience with Rust's type system ;)

lakwet commented 2 years ago

Hi, sorry for this late response. I will have a look this evening, after work.

lakwet commented 2 years ago

As it is written in the doc : https://docs.rs/voracious_radix_sort/latest/voracious_radix_sort/

The struct must be mapped to a key. The key must be among the aforementioned types (bool, char, f32, etc...).

Type T in the Radixable trait must be a primitive type : u8 .. u128 or i8 .. i128 or f32 or f64 or char or usize or isize or bool