# safina-timer

[![crates.io version](https://img.shields.io/crates/v/safina-timer.svg)](https://crates.io/crates/safina-timer)
[![license: Apache 2.0](https://gitlab.com/leonhard-llc/safina-rs/-/raw/main/license-apache-2.0.svg)](http://www.apache.org/licenses/LICENSE-2.0)
[![unsafe forbidden](https://gitlab.com/leonhard-llc/safina-rs/-/raw/main/unsafe-forbidden-success.svg)](https://github.com/rust-secure-code/safety-dance/)
[![pipeline status](https://gitlab.com/leonhard-llc/safina-rs/badges/main/pipeline.svg)](https://gitlab.com/leonhard-llc/safina-rs/-/pipelines)

This is a safe Rust library providing async `sleep_for` and `sleep_until` functions.
These functions return futures that complete at the specified time.

It is part of [`safina`](https://crates.io/crates/safina), a safe async runtime.

## Features
- `forbid(unsafe_code)`
- Depends only on `std`
- Good test coverage (95%)
- Source of time is
  [`std::thread::park_timeout`](https://doc.rust-lang.org/std/thread/fn.park_timeout.html)
  via
  [`std::sync::mpsc::Receiver::recv_timeout`](https://doc.rust-lang.org/std/sync/mpsc/struct.Receiver.html#method.recv_timeout).
- Works with [`safina-executor`](https://crates.io/crates/safina-executor) or any async executor

## Limitations
- Requires Rust `nightly`, for [OnceCell](https://doc.rust-lang.org/std/lazy/struct.OnceCell.html)
- Timers complete around 2ms late, but never early
- Allocates memory

## Examples
```rust
safina_timer::start_timer_thread();
safina_timer::sleep_for(Duration::from_secs(10)).await;
```

```rust
safina_timer::start_timer_thread();
let deadline =
    Instant::now() + Duration::from_millis(500);
safina_timer::sleep_until(deadline).await;
```

```rust
use safina_timer::with_deadline;
safina_timer::start_timer_thread();
let deadline =
    Instant::now() + Duration::from_millis(500);
let req =
    with_deadline(read_request(), deadline).await??;
let data =
    with_deadline(read_data(req), deadline).await??;
with_deadline(write_data(data), deadline).await??;
with_deadline(send_response(data), deadline).await??;
```

```rust
use safina_timer::with_timeout;
safina_timer::start_timer_thread();
let req = with_timeout(
    read_request(), Duration::from_millis(500)
).await??;
let data = with_timeout(
    read_data(req), Duration::from_millis(1000)
).await??;
with_timeout(
    write_data(data), Duration::from_millis(1000)
).await??;
with_timeout(
    send_response(data), Duration::from_millis(5000)
).await??;
```

## Documentation
https://docs.rs/safina-timer

## Alternatives
- [futures-timer](https://crates.io/crates/futures-timer)
  - popular
  - Supports: Wasm, Linux, Windows, macOS
  - Contains generous amounts of `unsafe` code
  - Uses `std::thread::park_timeout` as its source of time
- [async-io](https://crates.io/crates/async-io)
  - popular
  - single and repeating timers
  - Supports: Linux, Windows, macOS, iOS, Android, and many others.
  - Uses [polling](https://crates.io/crates/polling) crate
    which makes unsafe calls to OS.
- [async-timer](https://crates.io/crates/async-timer)
  - Supports: Linux & Android
  - Makes unsafe calls to OS
- [tokio](https://crates.io/crates/tokio)
  - very popular
  - single and repeating timers
  - Supports: Linux, macOS, other unix-like OSes, Windows
  - Fast, internally complicated, and full of `unsafe`
- [embedded-async-timer](https://crates.io/crates/embedded-async-timer)
  - no_std
  - Supports: bare_metal
## Release Process
1. Edit `Cargo.toml` and bump version number.
1. Run `./release.sh`

## Changelog
- v0.1.3 - Add badges to readme
- v0.1.2
  - Update [`with_deadline`](https://docs.rs/safina-timer/latest/safina_timer/fn.with_deadline.html)
    and [`with_timeout`](https://docs.rs/safina-timer/latest/safina_timer/fn.with_timeout.html):
    - Make them panic on TimerThreadNotStarted error and
      return new [`DeadlineExceeded`](https://docs.rs/safina-timer/latest/safina_timer/struct.DeadlineExceeded.html)
      struct instead of DeadlineError enum.
      This allows callers to write a match clause like `Err(DeadlineExceeded)`.
    - Make them use
      [`std::boxed::Box::pin`](https://doc.rust-lang.org/stable/std/boxed/struct.Box.html#method.pin)
      so callers don't have to.
  - Make [`sleep_until`](https://docs.rs/safina-timer/latest/safina_timer/fn.sleep_until.html)
    and [`sleep_for`](https://docs.rs/safina-timer/latest/safina_timer/fn.sleep_for.html)
    return `()` and
    panic if [`start_timer_thread()`](fn.start_timer_thread.html) has not been called.
- v0.1.1
  - Use most recent waker passed to `SleepFuture::poll`, as required by the
    [`std::future::Future::poll`](https://doc.rust-lang.org/stable/std/future/trait.Future.html#tymethod.poll)
    contract.
  - Add [`with_deadline`](https://docs.rs/safina-timer/latest/safina_timer/fn.with_deadline.html)
    and [`with_timeout`](https://docs.rs/safina-timer/latest/safina_timer/fn.with_timeout.html)
    functions.
- v0.1.0 - First published version

## TO DO
- DONE - Implement `sleep_until`
- DONE - Implement `sleep_for`
- DONE - Add tests
- Add docs
- Publish on crates.io

License: Apache-2.0
