0

Given this trait:

use std::io::{self, Read};
use std::fs::File;

pub trait Asset<D> {
    fn load_data(path: &str) -> io::Result<D>
    where
        D: From<Vec<u8>>
    {
        let file = File::open(path)?;
        let bytes_result: io::Result<Vec<u8>> = file.bytes().collect();

        Ok(D::from(bytes_result?))
    }

    // many more methods...
}

the load_data method is only available when D implements From<Vec<u8>>, which makes sense. However, I would like every type implementing Asset<D> to have load_data, where if D implements From<Vec<u8>>, then it uses the default implementation. Otherwise, the type would have to implement load_data itself.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
rytone
  • 155
  • 2
  • 11

1 Answers1

1

You can have a blanket implementation of the trait for any type that implements From<Vec<u8>> instead:

use std::io::{self, Read};
use std::fs::File;

pub trait Asset<D> {
    fn load_data(path: &str) -> io::Result<D>;

    // many more methods...
}

impl<D> Asset<D> for D
where
    D: From<Vec<u8>>,
{
    fn load_data(path: &str) -> io::Result<D> {
        let file = File::open(path)?;
        let bytes_result: io::Result<Vec<u8>> = file.bytes().collect();

        Ok(D::from(bytes_result?))
    }
}

struct Other;

impl Asset<Other> for Other {
    fn load_data(_path: &str) -> io::Result<Other> {
        unimplemented!()
    }
}

impl Asset<f64> for Other {
    fn load_data(_path: &str) -> io::Result<f64> {
        unimplemented!()
    }
}

You probably want to use Into instead of From (it's the opposite logic as When should I implement std::convert::From vs std::convert::Into?)

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366