How to define a fn that can take a &T or a U: Deref<Target = T>?

EDIT: See my comment below for a complete, working mimimal example reproducing the error.

I have the following code below, where a function has a trait bound to dereference some container object C to a target Group. I would like to also be able to pass in an object of type Group directly, but fail to do so. This seems to be because Group implements Deref<Target = Location>. Since Target is an associated type and not a type parameter, I guess herein lies the problem.

Question: how do I define a function that can either take a &T directly, or a &U with U: Deref<Target = T>?

The following gives the error:

error[E0271]: type mismatch resolving `<hdf5::hl::group::Group as std::ops::Deref>::Target == hdf5::hl::group::Group`
   --> simulate/src/checkpoint.rs:103:14
    |
103 |         data.to_hdf5(&group)?;
    |              ^^^^^^^ expected struct `hdf5::hl::location::Location`, found struct `hdf5::hl::group::Group`
    |
    = note: expected type `hdf5::hl::location::Location`
               found type `hdf5::hl::group::Group`
pub trait ToHdf5 {
    fn to_hdf5<C: ops::Deref<Target = hdf5::Group>>(&self, target: C) -> hdf5::Result<()>;
}

struct Checkpoint {
    file: hdf5::File,
}

impl Checkpoint {
    pub fn insert_data<C: ToHdf5>(&mut self, data: &C) -> Result<()> {
        let group = self.hdf5_file.group(GROUP_DATA)?;
        data.to_hdf5(group)?;
        self.next_checkpoint()
    }
}

Just take &T and deref coercions should allow &U as well.

That’s actually what I tried right after this post, same result, unfortunately.

What are you trying to do? I see the code snippet, but I don’t have enough context to meaningfully help.

1 Like

The hdf5 crate has two types, hdf5::File and hdf5::Group, that have a function new_dataset, see File::new_dataset and Group::new_dataset.

Now, File::new_dataset is implemented via a Deref trait, see impl Deref<Target=Group> for File.

I want to implement a function ToHDF5::to_hdf5 that can take an object that can derefence to a hdf5::Group, so that I can call its new_dataset method.

Below is a minimal example showing my problem. Just add hdf5 = "0.5" to your Cargo.toml:

use std::error::Error;
use std::ops;

trait ToHdf5 {
    /// This function should be able to take hdf5::File or a hdf5::Group.
    /// hdf5::File has a few functions that are implemented via it derefencing to a hdf5::Group
    fn to_hdf5<C: ops::Deref<Target = hdf5::Group>>(&self, target: &C) -> hdf5::Result<()>;
}

struct Checkpoint {
    hdf5_file: hdf5::File,
}

impl Checkpoint {
    pub fn insert_data<C: ToHdf5>(&mut self, data: &C) -> Result<(), Box<Error>> {
        let group = self.hdf5_file.group("data group")?;
        data.to_hdf5(&group)?;
        Ok(())
    }
}

fn main() {
}

I was having a brainfart. hdf5::File dereferences to hdf5::Group. So if I have function fn f(g: &hdf5::Group) and an object a: hdf5::File, then I can simply call f(&a), and &a will get derefernced to hdf5::Group.

2 Likes

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.