real-async-trait 0.0.2

A proc macro that uses experimental features to work around type erasure for async traits
Documentation
#![feature(generic_associated_types, type_alias_impl_trait)]
extern crate real_async_trait;

use std::collections::BTreeMap;
use std::str;

use real_async_trait::real_async_trait;

pub type Errno = usize;
pub const ENOENT: usize = 1;
pub const EBADF: usize = 2;

#[real_async_trait]
pub trait AsyncScheme {
    async fn open<'a>(&'a mut self, path: &'a [u8], flags: usize) -> Result<usize, Errno>;
    async fn close<'a>(&'a mut self, fd: usize) -> Result<(), Errno>;
    async fn read<'a>(&'a mut self, fd: usize, num: &'a mut u64) -> Result<(), Errno>;
    async fn write<'a>(&'a mut self, fd: usize, num: &'a u64) -> Result<(), Errno>;
}

struct NumberScheme {
    handles: BTreeMap<usize, u64>,
}

#[real_async_trait]
impl AsyncScheme for NumberScheme {
    async fn open<'a>(&'a mut self, path: &'a [u8], _flags: usize) -> Result<usize, Errno> {
        let path_str = str::from_utf8(path).or(Err(ENOENT))?;
        let num = path_str.parse::<usize>().or(Err(ENOENT))?;
        self.handles.insert(num, 0);
        Ok(num)
    }
    async fn close<'a>(&'a mut self, fd: usize) -> Result<(), Errno> {
        if self.handles.remove(&fd).is_none() {
            return Err(EBADF);
        }
        Ok(())
    }
    async fn read<'a>(&'a mut self, fd: usize, num: &'a mut u64) -> Result<(), Errno> {
        let handle = self.handles.get(&fd).ok_or(ENOENT)?;
        *num = *handle;
        Ok(())
    }
    async fn write<'a>(&'a mut self, fd: usize, num: &'a u64) -> Result<(), Errno> {
        let handle = self.handles.get_mut(&fd).ok_or(ENOENT)?;
        *handle = *num;
        Ok(())
    }
}

#[async_std::main]
async fn main() -> Result<(), Errno> {
    let mut numberscheme = NumberScheme {
        handles: BTreeMap::new(),
    };

    let mut number_buf = 0u64;
    let input_buf = 420u64;

    println!("Opening valuable number container `1337`");
    let fd = numberscheme.open(b"1337", 1).await?;
    println!("Opened number container `1337`");

    println!(
        "Initiating read from number container `1337` (fd {}), into buffer at {:p}",
        fd, &number_buf as *const _
    );
    numberscheme.read(fd, &mut number_buf).await?;
    println!(
        "Completed read from number container `1337` (fd {}), new value: {}",
        fd, number_buf
    );

    println!(
        "Initiating write into number container `1337` (fd {}), from buffer at {:p}",
        fd, &input_buf as *const _
    );
    numberscheme.write(fd, &input_buf).await?;
    println!(
        "Completed write into number container `1337` (fd {}), new value: {}",
        fd, input_buf
    );

    println!(
        "Initiating second read from number container `1337` (fd {}), into buffer at {:p}",
        fd, &number_buf as *const _
    );
    numberscheme.read(fd, &mut number_buf).await?;
    println!(
        "Completed second read from number container `1337` (fd {}), new value: {}",
        fd, number_buf
    );

    println!("Closing number container `1337` (fd {})", fd);
    numberscheme.close(fd).await?;
    println!("Number container `1337` (fd {}) closed", fd);

    Ok(())
}