pub mod net;
pub mod crypto;
#[cfg(feature = "crypto-p256")]
pub mod crypto_p256;
pub mod atomic64 {
#[cfg(target_has_atomic = "64")]
pub use core::sync::atomic::AtomicU64;
#[cfg(not(target_has_atomic = "64"))]
#[derive(Debug, Default)]
pub struct AtomicU64(core::sync::atomic::AtomicU32);
#[cfg(not(target_has_atomic = "64"))]
impl AtomicU64 {
pub const fn new(v: u64) -> Self {
Self(core::sync::atomic::AtomicU32::new(v as u32))
}
pub fn load(&self, o: core::sync::atomic::Ordering) -> u64 {
self.0.load(o) as u64
}
pub fn store(&self, v: u64, o: core::sync::atomic::Ordering) {
self.0.store(v as u32, o)
}
pub fn fetch_add(&self, v: u64, o: core::sync::atomic::Ordering) -> u64 {
self.0.fetch_add(v as u32, o) as u64
}
pub fn fetch_sub(&self, v: u64, o: core::sync::atomic::Ordering) -> u64 {
self.0.fetch_sub(v as u32, o) as u64
}
pub fn swap(&self, v: u64, o: core::sync::atomic::Ordering) -> u64 {
self.0.swap(v as u32, o) as u64
}
}
}
pub mod rng {
use crate::platform::sync::Mutex;
type FillFn = fn(&mut [u8]);
static FILL_FN: Mutex<Option<FillFn>> = Mutex::new(None);
pub fn set_fill_fn(f: FillFn) {
*FILL_FN.lock() = Some(f);
}
pub fn fill(buf: &mut [u8]) {
#[cfg(feature = "std")]
{
use rand::Rng;
rand::rng().fill_bytes(buf);
}
#[cfg(not(feature = "std"))]
{
let fill =
(*FILL_FN.lock()).expect("platform::rng: set_fill_fn not called before fill");
fill(buf);
}
}
#[cfg(target_arch = "xtensa")]
#[unsafe(no_mangle)]
unsafe fn __getrandom_custom(dest: *mut u8, len: usize) -> u32 {
let slice = unsafe { core::slice::from_raw_parts_mut(dest, len) };
fill(slice);
0
}
}
pub mod dns {
use crate::errors::RtcResult;
use alloc::vec::Vec;
use core::net::SocketAddr;
#[cfg(feature = "std")]
pub async fn lookup_host(host: &str) -> RtcResult<Vec<SocketAddr>> {
let addrs = tokio::net::lookup_host(host)
.await
.map_err(|e| crate::errors::RtcError::Internal(alloc::format!("dns: {e}")))?;
Ok(addrs.collect())
}
#[cfg(not(feature = "std"))]
pub async fn lookup_host(_host: &str) -> RtcResult<Vec<SocketAddr>> {
Err(crate::errors::RtcError::Internal(
alloc::string::String::from("dns: no resolver wired (WP3)"),
))
}
}
#[cfg(not(feature = "std"))]
pub mod sync_embedded;
pub mod select {
use core::future::Future;
use core::pin::Pin;
use core::task::{Context, Poll};
impl<A, B> Future for Either<A, B>
where
A: Future + Unpin,
B: Future<Output = A::Output> + Unpin,
{
type Output = A::Output;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
match self.get_mut() {
Either::A(a) => Pin::new(a).poll(cx),
Either::B(b) => Pin::new(b).poll(cx),
}
}
}
#[inline]
fn poll_unpin<F: Future + Unpin>(fut: &mut F, cx: &mut Context<'_>) -> Poll<F::Output> {
Pin::new(fut).poll(cx)
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Either<A, B> {
A(A),
B(B),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Which3<A, B, C> {
A(A),
B(B),
C(C),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Which4<A, B, C, D> {
A(A),
B(B),
C(C),
D(D),
}
#[must_use = "futures do nothing unless you `.await` or poll them"]
pub struct Select2<A: Future, B: Future> {
a: A,
b: B,
}
pub fn select2<A: Future, B: Future>(a: A, b: B) -> Select2<A, B> {
Select2 { a, b }
}
impl<A: Future + Unpin, B: Future + Unpin> Future for Select2<A, B> {
type Output = Either<A::Output, B::Output>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.get_mut();
if let Poll::Ready(v) = poll_unpin(&mut this.a, cx) {
return Poll::Ready(Either::A(v));
}
if let Poll::Ready(v) = poll_unpin(&mut this.b, cx) {
return Poll::Ready(Either::B(v));
}
Poll::Pending
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Which5<A, B, C, D, E> {
A(A),
B(B),
C(C),
D(D),
E(E),
}
#[must_use = "futures do nothing unless you `.await` or poll them"]
pub struct Select3<A: Future, B: Future, C: Future> {
a: A,
b: B,
c: C,
}
pub fn select3<A: Future, B: Future, C: Future>(a: A, b: B, c: C) -> Select3<A, B, C> {
Select3 { a, b, c }
}
impl<A: Future + Unpin, B: Future + Unpin, C: Future + Unpin> Future for Select3<A, B, C> {
type Output = Which3<A::Output, B::Output, C::Output>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.get_mut();
if let Poll::Ready(v) = poll_unpin(&mut this.a, cx) {
return Poll::Ready(Which3::A(v));
}
if let Poll::Ready(v) = poll_unpin(&mut this.b, cx) {
return Poll::Ready(Which3::B(v));
}
if let Poll::Ready(v) = poll_unpin(&mut this.c, cx) {
return Poll::Ready(Which3::C(v));
}
Poll::Pending
}
}
#[must_use = "futures do nothing unless you `.await` or poll them"]
pub struct Select5<A: Future, B: Future, C: Future, D: Future, E: Future> {
a: A,
b: B,
c: C,
d: D,
e: E,
}
pub fn select5<A: Future, B: Future, C: Future, D: Future, E: Future>(
a: A,
b: B,
c: C,
d: D,
e: E,
) -> Select5<A, B, C, D, E> {
Select5 { a, b, c, d, e }
}
impl<
A: Future + Unpin,
B: Future + Unpin,
C: Future + Unpin,
D: Future + Unpin,
E: Future + Unpin,
> Future for Select5<A, B, C, D, E>
{
type Output = Which5<A::Output, B::Output, C::Output, D::Output, E::Output>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.get_mut();
if let Poll::Ready(v) = poll_unpin(&mut this.a, cx) {
return Poll::Ready(Which5::A(v));
}
if let Poll::Ready(v) = poll_unpin(&mut this.b, cx) {
return Poll::Ready(Which5::B(v));
}
if let Poll::Ready(v) = poll_unpin(&mut this.c, cx) {
return Poll::Ready(Which5::C(v));
}
if let Poll::Ready(v) = poll_unpin(&mut this.d, cx) {
return Poll::Ready(Which5::D(v));
}
if let Poll::Ready(v) = poll_unpin(&mut this.e, cx) {
return Poll::Ready(Which5::E(v));
}
Poll::Pending
}
}
#[must_use = "futures do nothing unless you `.await` or poll them"]
pub struct Select4<A: Future, B: Future, C: Future, D: Future> {
a: A,
b: B,
c: C,
d: D,
}
pub fn select4<A: Future, B: Future, C: Future, D: Future>(
a: A,
b: B,
c: C,
d: D,
) -> Select4<A, B, C, D> {
Select4 { a, b, c, d }
}
impl<A: Future + Unpin, B: Future + Unpin, C: Future + Unpin, D: Future + Unpin> Future
for Select4<A, B, C, D>
{
type Output = Which4<A::Output, B::Output, C::Output, D::Output>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.get_mut();
if let Poll::Ready(v) = poll_unpin(&mut this.a, cx) {
return Poll::Ready(Which4::A(v));
}
if let Poll::Ready(v) = poll_unpin(&mut this.b, cx) {
return Poll::Ready(Which4::B(v));
}
if let Poll::Ready(v) = poll_unpin(&mut this.c, cx) {
return Poll::Ready(Which4::C(v));
}
if let Poll::Ready(v) = poll_unpin(&mut this.d, cx) {
return Poll::Ready(Which4::D(v));
}
Poll::Pending
}
}
}
pub mod time {
#[cfg(not(feature = "std"))]
use crate::platform::atomic64::AtomicU64;
#[cfg(not(feature = "std"))]
use core::sync::atomic::Ordering;
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct Instant {
ms: u64,
}
impl Instant {
pub fn now() -> Self {
#[cfg(feature = "std")]
{
let ms = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.map(|d| d.as_millis() as u64)
.unwrap_or(0);
Self { ms }
}
#[cfg(not(feature = "std"))]
{
Self {
ms: NOW_MS.load(Ordering::Relaxed),
}
}
}
pub fn elapsed(&self) -> core::time::Duration {
#[cfg(feature = "std")]
{
let now_ms = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.map(|d| d.as_millis() as u64)
.unwrap_or(0);
core::time::Duration::from_millis(now_ms.saturating_sub(self.ms))
}
#[cfg(not(feature = "std"))]
{
core::time::Duration::from_millis(
NOW_MS.load(Ordering::Relaxed).saturating_sub(self.ms),
)
}
}
pub fn duration_since(&self, earlier: Self) -> core::time::Duration {
core::time::Duration::from_millis(self.ms.saturating_sub(earlier.ms))
}
}
impl core::ops::Add<core::time::Duration> for Instant {
type Output = Instant;
fn add(self, rhs: core::time::Duration) -> Instant {
Instant {
ms: self.ms.saturating_add(rhs.as_millis() as u64),
}
}
}
impl core::ops::Sub<core::time::Duration> for Instant {
type Output = Instant;
fn sub(self, rhs: core::time::Duration) -> Instant {
Instant {
ms: self.ms.saturating_sub(rhs.as_millis() as u64),
}
}
}
#[cfg(not(feature = "std"))]
static NOW_MS: AtomicU64 = AtomicU64::new(0);
#[cfg(not(feature = "std"))]
pub fn advance_ms(ms: u64) {
NOW_MS.fetch_add(ms.max(1), Ordering::Relaxed);
}
#[cfg(not(feature = "std"))]
pub fn set_now_ms(ms: u64) {
NOW_MS.store(ms, Ordering::Relaxed);
}
#[cfg(feature = "std")]
pub fn unix_ms() -> Option<u64> {
Some(
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.map(|d| d.as_millis() as u64)
.unwrap_or(0),
)
}
#[cfg(not(feature = "std"))]
pub fn unix_ms() -> Option<u64> {
None
}
#[cfg(not(feature = "std"))]
pub async fn with_timeout<F: Future>(
dur: core::time::Duration,
fut: F,
) -> core::result::Result<F::Output, ()> {
use crate::platform::select::{Either, select2};
let mut fut = core::pin::pin!(fut);
let timer = alloc::boxed::Box::pin(super::task::sleep(dur));
match select2(timer, &mut fut).await {
Either::A(_) => Err(()),
Either::B(out) => Ok(out),
}
}
#[cfg(feature = "std")]
pub async fn with_timeout<F: core::future::Future>(
dur: core::time::Duration,
fut: F,
) -> core::result::Result<F::Output, tokio::time::error::Elapsed> {
tokio::time::timeout(dur, fut).await
}
}
#[cfg(feature = "std")]
pub mod task {
use core::future::Future;
pub fn spawn<F>(fut: F) -> tokio::task::JoinHandle<F::Output>
where
F: Future + Send + 'static,
F::Output: Send + 'static,
{
tokio::spawn(fut)
}
pub async fn sleep(dur: core::time::Duration) {
tokio::time::sleep(dur).await;
}
pub async fn yield_now() {
tokio::task::yield_now().await;
}
pub struct Interval(tokio::time::Interval);
impl Interval {
pub async fn tick(&mut self) {
self.0.tick().await;
}
pub fn set_missed_tick_behavior(&mut self, behavior: MissedTickBehavior) {
self.0.set_missed_tick_behavior(match behavior {
MissedTickBehavior::Burst => tokio::time::MissedTickBehavior::Burst,
MissedTickBehavior::Delay => tokio::time::MissedTickBehavior::Delay,
MissedTickBehavior::Skip => tokio::time::MissedTickBehavior::Skip,
});
}
}
#[derive(Debug, Clone, Copy)]
pub enum MissedTickBehavior {
Burst,
Delay,
Skip,
}
pub fn interval_after(delay: core::time::Duration, period: core::time::Duration) -> Interval {
Interval(tokio::time::interval_at(
tokio::time::Instant::now() + delay,
period,
))
}
}
#[cfg(not(feature = "std"))]
pub mod task {
use alloc::boxed::Box;
use core::future::Future;
use core::pin::Pin;
use core::task::{Context, Poll};
pub type BoxedTask = Box<dyn Future<Output = ()> + Send>;
enum Spawner {
Fn(fn(BoxedTask)),
Dyn(&'static (dyn Fn(BoxedTask) + Send + Sync)),
}
static SPAWN_FN: crate::platform::sync::Mutex<Option<Spawner>> =
crate::platform::sync::Mutex::new(None);
pub fn set_spawn_fn(f: fn(BoxedTask)) {
*SPAWN_FN.lock() = Some(Spawner::Fn(f));
}
pub fn set_spawner(f: &'static (dyn Fn(BoxedTask) + Send + Sync)) {
*SPAWN_FN.lock() = Some(Spawner::Dyn(f));
}
pub fn spawn<F>(fut: F)
where
F: Future<Output = ()> + Send + 'static,
{
let spawner = SPAWN_FN.lock();
let Some(spawner) = spawner.as_ref() else {
panic!("platform::task::set_spawn_fn not called");
};
match spawner {
Spawner::Fn(f) => f(Box::new(fut)),
Spawner::Dyn(f) => f(Box::new(fut)),
}
}
type SleepFn = fn(core::time::Duration) -> Pin<Box<dyn Future<Output = ()> + Send>>;
static SLEEP_FN: crate::platform::sync::Mutex<Option<SleepFn>> =
crate::platform::sync::Mutex::new(None);
pub fn set_sleep_fn(f: SleepFn) {
*SLEEP_FN.lock() = Some(f);
}
pub async fn sleep(dur: core::time::Duration) {
let fut = {
let f = SLEEP_FN
.lock()
.expect("platform::task::set_sleep_fn not called");
f(dur)
};
fut.await;
}
pub async fn yield_now() {
struct YieldNow(bool);
impl Future for YieldNow {
type Output = ();
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
if self.0 {
Poll::Ready(())
} else {
self.0 = true;
cx.waker().wake_by_ref();
Poll::Pending
}
}
}
YieldNow(false).await;
}
pub struct Interval {
first: Option<core::time::Duration>,
period: core::time::Duration,
}
impl Interval {
pub async fn tick(&mut self) {
let dur = self.first.take().unwrap_or(self.period);
sleep(dur).await;
}
pub fn set_missed_tick_behavior(&mut self, _behavior: MissedTickBehavior) {}
}
#[derive(Debug, Clone, Copy)]
pub enum MissedTickBehavior {
Burst,
Delay,
Skip,
}
pub fn interval_after(delay: core::time::Duration, period: core::time::Duration) -> Interval {
Interval {
first: Some(delay),
period,
}
}
}
pub mod join {
use core::future::Future;
use core::pin::Pin;
use core::task::{Context, Poll};
#[must_use = "futures do nothing unless you `.await` or poll them"]
pub struct Join2<A: Future, B: Future> {
a: Option<A>,
b: Option<B>,
a_out: Option<A::Output>,
b_out: Option<B::Output>,
}
pub fn join2<A: Future, B: Future>(a: A, b: B) -> Join2<A, B> {
Join2 {
a: Some(a),
b: Some(b),
a_out: None,
b_out: None,
}
}
impl<A: Future + Unpin, B: Future + Unpin> Future for Join2<A, B> {
type Output = (A::Output, B::Output);
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = unsafe { self.get_unchecked_mut() };
if this.a_out.is_none()
&& let Some(a) = this.a.as_mut()
&& let Poll::Ready(v) = Pin::new(a).poll(cx)
{
this.a_out = Some(v);
this.a = None;
}
if this.b_out.is_none()
&& let Some(b) = this.b.as_mut()
&& let Poll::Ready(v) = Pin::new(b).poll(cx)
{
this.b_out = Some(v);
this.b = None;
}
match (this.a_out.take(), this.b_out.take()) {
(Some(a), Some(b)) => Poll::Ready((a, b)),
(a, b) => {
this.a_out = a;
this.b_out = b;
Poll::Pending
}
}
}
}
#[must_use = "futures do nothing unless you `.await` or poll them"]
pub struct Join3<A: Future, B: Future, C: Future> {
a: Option<A>,
b: Option<B>,
c: Option<C>,
a_out: Option<A::Output>,
b_out: Option<B::Output>,
c_out: Option<C::Output>,
}
pub fn join3<A: Future, B: Future, C: Future>(a: A, b: B, c: C) -> Join3<A, B, C> {
Join3 {
a: Some(a),
b: Some(b),
c: Some(c),
a_out: None,
b_out: None,
c_out: None,
}
}
impl<A: Future + Unpin, B: Future + Unpin, C: Future + Unpin> Future for Join3<A, B, C> {
type Output = (A::Output, B::Output, C::Output);
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = unsafe { self.get_unchecked_mut() };
if this.a_out.is_none()
&& let Some(a) = this.a.as_mut()
&& let Poll::Ready(v) = Pin::new(a).poll(cx)
{
this.a_out = Some(v);
this.a = None;
}
if this.b_out.is_none()
&& let Some(b) = this.b.as_mut()
&& let Poll::Ready(v) = Pin::new(b).poll(cx)
{
this.b_out = Some(v);
this.b = None;
}
if this.c_out.is_none()
&& let Some(c) = this.c.as_mut()
&& let Poll::Ready(v) = Pin::new(c).poll(cx)
{
this.c_out = Some(v);
this.c = None;
}
match (this.a_out.take(), this.b_out.take(), this.c_out.take()) {
(Some(a), Some(b), Some(c)) => Poll::Ready((a, b, c)),
(a, b, c) => {
this.a_out = a;
this.b_out = b;
this.c_out = c;
Poll::Pending
}
}
}
}
}
#[cfg(feature = "std")]
pub mod sync {
pub mod watch {
pub use tokio::sync::watch::{Receiver, Sender, channel, error::RecvError};
}
pub mod mpsc {
pub use tokio::sync::mpsc::error::{SendError, TrySendError};
pub use tokio::sync::mpsc::{
Receiver, Sender, UnboundedReceiver, UnboundedSender, channel, unbounded_channel,
};
}
pub mod oneshot {
pub use tokio::sync::oneshot::{Receiver, Sender, channel};
}
pub mod broadcast {
pub use tokio::sync::broadcast::error::TryRecvError;
pub use tokio::sync::broadcast::{Receiver, Sender, channel, error::RecvError};
}
pub use parking_lot::{Mutex, MutexGuard, RwLock, RwLockReadGuard, RwLockWriteGuard};
pub use std::sync::OnceLock;
pub use tokio::sync::Mutex as AsyncMutex;
pub use tokio::sync::Notify;
}
#[cfg(not(feature = "std"))]
pub mod sync {
pub use crate::platform::sync_embedded::Notify;
pub use crate::platform::sync_embedded::OnceLock;
pub use crate::platform::sync_embedded::broadcast;
pub use crate::platform::sync_embedded::mpsc;
pub use crate::platform::sync_embedded::oneshot;
pub use crate::platform::sync_embedded::watch;
pub use crate::platform::sync_embedded::{AsyncMutex, Mutex, MutexGuard};
pub use crate::platform::sync_embedded::{RwLock, RwLockReadGuard, RwLockWriteGuard};
}