Looking for threaded/async tips for a specific problem (handing over writer socket)

I decided to go a completely different route and try to use a custom future. The idea being that each HasherFuture launches a thread which hashes the function and reports back once its done.

Using:

sha2 = "0.8.0"
hex = "0.4.0"

I used the example code from the async book and got this:

use {
  std::{
    future::Future,
    sync::{Arc,Mutex},
    task::{Context,Poll,Waker},
    pin::Pin,
    thread,
    path::PathBuf
  },
  sha2::{Sha256, Digest}
};


pub struct HasherFuture {
  shared_state: Arc<Mutex<SharedState>>
}

struct SharedState {
  waker: Option<Waker>,
  hash: Option<String>,
  id: String
}

pub struct HashRet {
  id: String,
  hash: String
}

impl Future for HasherFuture {
  type Output = HashRet;
  fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> {
    let mut shared_state = self.shared_state.lock().unwrap();
    if let Some(hash) = &shared_state.hash {
      let hr = HashRet { id: shared_state.id.clone(), hash: hash.clone() };
      Poll::Ready(hr)
    } else {
      shared_state.waker = Some(ctx.waker().clone());
      Poll::Pending
    }
  }
}

impl HasherFuture {
  pub fn new(id: &str, fname: &PathBuf) -> Self {
    let shstate = SharedState { waker: None, hash: None, id: id.to_string() };
    let shared_state = Arc::new(Mutex::new(shstate));

    let mut file = std::fs::File::open(&fname).expect("Unable to open file");
    let mut sha256 = Sha256::new();

    let thread_shared_state = shared_state.clone();
    thread::spawn(move || {
      let _n = std::io::copy(&mut file, &mut sha256);
      let hash = sha256.result();
      let mut shared_state = thread_shared_state.lock().unwrap();
      shared_state.hash = Some(hex::encode(hash));
      if let Some(waker) = shared_state.waker.take() {
        waker.wake()
      }
    });

    HasherFuture { shared_state }
  }
}

How do I actually utilize this from, say, async-std? I know the async keyword is supposed to create a function which returns a future which needs to be fed to an executor -- but how does rust know it is supposed to create a HasherFuture as a return type? I assume that's not how it's supposed to work, which means that I'm suffering from a rather large knowledge gap here.