Crate smelling_salts

source ·
Expand description

Abstraction over OS APIs to handle asynchronous device waking.

Getting Started

Most devices are represented as file descriptors on unix-like operating systems (MacOS also has run loops). On Windows, devices are usually sockets or handles. WebAssembly running in the browser doesn’t have a equivalent. To get around these device backend differences, Smelling Salts exposed an OsDevice type which has From conversions implemented for the platform types.

An OsDevice by itself isn’t that useful, though. When you have a handle to a device, you want to asynchronously watch it for events. For this, you construct a Device, which implements Notify. But, general devices aren’t that useful either, so you’ll need to wrap it in your own custom type. Usually, you will filter out some of the events, so you’ll need to implement Notify.

Here’s a simple example implementing a Notify for stdin line reading:

use std::{
    io::{self, BufRead, BufReader},
    os::fd::AsFd,
};

use async_main::{async_main, Spawn};
use pasts::prelude::*;
use smelling_salts::{Device, Watch};

/// A `Stdin` device future.
pub struct Stdin(BufReader<Device>);

impl Default for Stdin {
    fn default() -> Self {
        Self::new()
    }
}

impl Stdin {
    /// Create a new `Stdin` device handle.
    pub fn new() -> Self {
        let owned_fd = io::stdin().as_fd().try_clone_to_owned().unwrap();
        let device = Device::new(owned_fd, Watch::INPUT);

        Self(BufReader::new(device))
    }
}

impl Notify for Stdin {
    type Event = String;

    fn poll_next(
        mut self: Pin<&mut Self>,
        task: &mut Task<'_>,
    ) -> Poll<String> {
        while let Ready(()) = Pin::new(self.0.get_mut()).poll_next(task) {
            let mut string = String::new();
            let Err(e) = self.0.read_line(&mut string) else {
                string.pop();
                return Ready(string);
            };

            dbg!(e);
        }

        Pending
    }
}

#[async_main]
async fn main(_spawner: impl Spawn) {
    let mut stdin = Stdin::new();

    loop {
        let you_said = stdin.next().await;

        println!("You said: \"{you_said}\"");
    }
}

Structs

  • An owned device handle that’s being watched for wake events
  • An owned handle to an unwatched OS device
  • A bitfield specifying which events to watch for