diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d62df86..77fd6e2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -42,6 +42,14 @@ jobs: if: startsWith(matrix.rust, 'nightly') run: cargo check -Z features=dev_dep - run: cargo test + - run: cargo test --no-default-features + - name: Install cargo-hack + uses: taiki-e/install-action@cargo-hack + - run: rustup target add thumbv7m-none-eabi + - name: Run cargo check (without dev-dependencies to catch missing feature flags) + run: cargo hack build --all --no-dev-deps + - run: cargo hack build --all --target thumbv7m-none-eabi --no-default-features --no-dev-deps + - run: cargo hack build --target thumbv7m-none-eabi --no-default-features --no-dev-deps --features portable-atomic msrv: runs-on: ubuntu-latest @@ -49,12 +57,13 @@ jobs: matrix: # When updating this, the reminder to update the minimum supported # Rust version in Cargo.toml. - rust: ['1.45'] + rust: ['1.59'] steps: - uses: actions/checkout@v3 - name: Install Rust run: rustup update ${{ matrix.rust }} && rustup default ${{ matrix.rust }} - run: cargo build + - run: cargo build --no-default-features clippy: runs-on: ubuntu-latest diff --git a/Cargo.toml b/Cargo.toml index 57fff5c..72983ec 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ name = "async-channel" version = "1.9.0" authors = ["Stjepan Glavina "] edition = "2018" -rust-version = "1.45" +rust-version = "1.59" description = "Async multi-producer multi-consumer channel" license = "Apache-2.0 OR MIT" repository = "https://github.com/smol-rs/async-channel" @@ -15,15 +15,19 @@ categories = ["asynchronous", "concurrency"] exclude = ["/.*"] [dependencies] -concurrent-queue = "2" -event-listener = "2.4.0" -event-listener-strategy = { git = "https://github.com/smol-rs/event-listener" } -futures-core = "0.3.5" +concurrent-queue = { version = "2", default-features = false } +event-listener = { version = "2.4.0", default-features = false } +event-listener-strategy = { git = "https://github.com/smol-rs/event-listener", default-features = false } +futures-core = { version = "0.3.5", default-features = false } pin-project-lite = "0.2.11" [dev-dependencies] easy-parallel = "3" futures-lite = "1" +[features] +default = ["std"] +std = ["concurrent-queue/std", "event-listener/std", "event-listener-strategy/std"] + [patch.crates-io] -event-listener = { git = "https://github.com/smol-rs/event-listener" } +event-listener = { git = "https://github.com/smol-rs/event-listener", default-features = false } diff --git a/src/lib.rs b/src/lib.rs index d3a6083..0820a88 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -26,6 +26,7 @@ //! # }); //! ``` +#![cfg_attr(not(feature = "std"), no_std)] #![forbid(unsafe_code)] #![warn(missing_docs, missing_debug_implementations, rust_2018_idioms)] #![doc( @@ -35,15 +36,16 @@ html_logo_url = "https://raw.githubusercontent.com/smol-rs/smol/master/assets/images/logo_fullsize_transparent.png" )] -use std::error; -use std::fmt; -use std::future::Future; -use std::pin::Pin; -use std::process; -use std::sync::atomic::{AtomicUsize, Ordering}; -use std::sync::Arc; -use std::task::{Context, Poll}; -use std::usize; +extern crate alloc; + +use core::fmt; +use core::future::Future; +use core::pin::Pin; +use core::sync::atomic::{AtomicUsize, Ordering}; +use core::task::{Context, Poll}; +use core::usize; + +use alloc::sync::Arc; use concurrent_queue::{ConcurrentQueue, PopError, PushError}; use event_listener::{Event, EventListener}; @@ -274,6 +276,7 @@ impl Sender { /// drop(r); /// assert_eq!(s.send_blocking(2), Err(SendError(2))); /// ``` + #[cfg(feature = "std")] pub fn send_blocking(&self, msg: T) -> Result<(), SendError> { self.send(msg).wait() } @@ -465,7 +468,7 @@ impl Clone for Sender { // Make sure the count never overflows, even if lots of sender clones are leaked. if count > usize::MAX / 2 { - process::abort(); + abort(); } Sender { @@ -596,6 +599,7 @@ impl Receiver { /// assert_eq!(r.recv_blocking(), Ok(1)); /// assert_eq!(r.recv_blocking(), Err(RecvError)); /// ``` + #[cfg(feature = "std")] pub fn recv_blocking(&self) -> Result { self.recv().wait() } @@ -778,7 +782,7 @@ impl Clone for Receiver { // Make sure the count never overflows, even if lots of receiver clones are leaked. if count > usize::MAX / 2 { - process::abort(); + abort(); } Receiver { @@ -864,7 +868,7 @@ impl WeakSender { Err(_) => None, Ok(new_value) if new_value > usize::MAX / 2 => { // Make sure the count never overflows, even if lots of sender clones are leaked. - process::abort(); + abort(); } Ok(_) => Some(Sender { channel: self.channel.clone(), @@ -910,7 +914,7 @@ impl WeakReceiver { Err(_) => None, Ok(new_value) if new_value > usize::MAX / 2 => { // Make sure the count never overflows, even if lots of receiver clones are leaked. - process::abort(); + abort(); } Ok(_) => Some(Receiver { channel: self.channel.clone(), @@ -948,7 +952,8 @@ impl SendError { } } -impl error::Error for SendError {} +#[cfg(feature = "std")] +impl std::error::Error for SendError {} impl fmt::Debug for SendError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -998,7 +1003,8 @@ impl TrySendError { } } -impl error::Error for TrySendError {} +#[cfg(feature = "std")] +impl std::error::Error for TrySendError {} impl fmt::Debug for TrySendError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -1024,7 +1030,8 @@ impl fmt::Display for TrySendError { #[derive(PartialEq, Eq, Clone, Copy, Debug)] pub struct RecvError; -impl error::Error for RecvError {} +#[cfg(feature = "std")] +impl std::error::Error for RecvError {} impl fmt::Display for RecvError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -1060,7 +1067,8 @@ impl TryRecvError { } } -impl error::Error for TryRecvError {} +#[cfg(feature = "std")] +impl std::error::Error for TryRecvError {} impl fmt::Display for TryRecvError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -1076,6 +1084,7 @@ easy_wrapper! { #[derive(Debug)] #[must_use = "futures do nothing unless you `.await` or poll them"] pub struct Send<'a, T>(SendInner<'a, T> => Result<(), SendError>); + #[cfg(feature = "std")] pub(crate) wait(); } @@ -1125,6 +1134,7 @@ easy_wrapper! { #[derive(Debug)] #[must_use = "futures do nothing unless you `.await` or poll them"] pub struct Recv<'a, T>(RecvInner<'a, T> => Result); + #[cfg(feature = "std")] pub(crate) wait(); } @@ -1166,3 +1176,20 @@ impl<'a, T> EventListenerFuture for RecvInner<'a, T> { } } } + +#[cfg(feature = "std")] +use std::process::abort; + +#[cfg(not(feature = "std"))] +fn abort() -> ! { + struct PanicOnDrop; + + impl Drop for PanicOnDrop { + fn drop(&mut self) { + panic!("Panic while panicking to abort"); + } + } + + let _bomb = PanicOnDrop; + panic!("Panic while panicking to abort") +} diff --git a/tests/bounded.rs b/tests/bounded.rs index abb8895..b525dfb 100644 --- a/tests/bounded.rs +++ b/tests/bounded.rs @@ -25,6 +25,7 @@ fn smoke() { assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); } +#[cfg(feature = "std")] #[test] fn smoke_blocking() { let (s, r) = bounded(1); @@ -459,6 +460,7 @@ fn mpmc_stream() { } } +#[cfg(feature = "std")] #[test] fn weak() { let (s, r) = bounded::(3); diff --git a/tests/unbounded.rs b/tests/unbounded.rs index 31d4987..90395a3 100644 --- a/tests/unbounded.rs +++ b/tests/unbounded.rs @@ -24,6 +24,7 @@ fn smoke() { assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); } +#[cfg(feature = "std")] #[test] fn smoke_blocking() { let (s, r) = unbounded(); @@ -318,6 +319,7 @@ fn mpmc_stream() { } } +#[cfg(feature = "std")] #[test] fn weak() { let (s, r) = unbounded::();