1
0
mirror of https://github.com/fafhrd91/actix-net synced 2025-08-15 03:20:33 +02:00

Compare commits

..

28 Commits

Author SHA1 Message Date
Rob Ede
8e9401f8e1 prepare bytestring release 1.2.1 2022-11-12 13:19:09 +00:00
VladimirBramstedt
9ede174e81 fix no_std compatibility (#471)
Co-authored-by: Yuki Okushi <jtitor@2k36.org>
2022-11-12 16:00:06 +09:00
Rob Ede
bb36e2a072 prepare bytestring release 1.2.0 2022-11-07 20:22:47 +00:00
Rob Ede
6061a44a22 slice_ref doc tweaks 2022-11-07 20:21:57 +00:00
Wang, Chi
363984ad75 Add ByteString::slice_ref (#470) 2022-11-07 20:16:46 +00:00
Rob Ede
00654aadc5 use direct tokio exports where possible 2022-10-30 20:25:13 +00:00
fakeshadow
428914e65e remove fakeshadow from author lists (#468) 2022-10-25 16:34:36 +01:00
Rob Ede
df9a9d1a1e don't install cargo-cache on 1.57 CI 2022-10-25 00:10:39 +01:00
Rob Ede
056d2cd573 workaround ci msrv issue 2022-10-24 23:44:29 +01:00
Rob Ede
68228a6cf2 update dev deps 2022-10-21 03:23:40 +01:00
Rob Ede
d5a9a6a1c5 prepare actix-utils release 3.0.1 2022-10-21 03:15:48 +01:00
Rob Ede
ade71b7bd3 address soundness footgun in poll_fn 2022-10-21 03:14:38 +01:00
Rob Ede
cb83922b29 add macos test note 2022-10-17 04:27:34 +01:00
Rob Ede
25209f5bd8 use impl-more in -tls 2022-10-17 04:14:09 +01:00
Rob Ede
c4a0f37d0c fix minimal versions for bytestring 2022-07-23 03:06:44 +01:00
Rob Ede
0e649329b9 fix minimal versions 2022-07-23 01:47:59 +01:00
Rob Ede
66756bc448 update all crates msrv to 1.57 (#464) 2022-07-23 00:51:12 +01:00
Iskandarov Lev
126ed4c2e3 normalize logs capital letter (#463)
Co-authored-by: Rob Ede <robjtede@icloud.com>
2022-07-22 20:53:06 +01:00
Yuki Okushi
283974f3e6 Make actix-codec an optional dependency (#459) 2022-06-23 17:27:36 +01:00
Yuki Okushi
bf2aa3902c Set depth of --feature-powerset on Windows CI (#460) 2022-06-12 02:17:38 +01:00
Rob Ede
71b4e55c92 prepare bytestring release 1.1.0 (#461) 2022-06-11 13:41:11 +01:00
Marcus Griep
eb5fa30ada feat: impls for Box and String conversions (#458)
Co-authored-by: Rob Ede <robjtede@icloud.com>
2022-06-11 04:22:34 +01:00
Rob Ede
49a034259f prepare local-waker release 0.1.3 2022-05-03 14:58:09 +01:00
Rob Ede
3337f63b4e prepare local-channel release 0.1.3 2022-05-03 14:56:40 +01:00
Rob Ede
86ce140249 ensure all crates include license files
closes #456
2022-05-03 14:55:49 +01:00
Guillaume Desmottes
635aebe887 actix-server: fix UNIX signal handling documentation (#455) 2022-05-03 13:37:18 +01:00
Rob Ede
4c1e581a54 add track_caller atrtibute to spawn calls (#454)
* add track_caller attribute to spawn calls

* fix ci
2022-04-25 21:05:48 +01:00
Rob Ede
dc67ba770d fmt with import grouping 2022-04-10 02:48:53 +01:00
73 changed files with 330 additions and 267 deletions

View File

@@ -14,13 +14,10 @@ ci-check = "hack --workspace --feature-powerset --exclude-features=io-uring chec
ci-check-linux = "hack --workspace --feature-powerset check --tests --examples" ci-check-linux = "hack --workspace --feature-powerset check --tests --examples"
# tests avoiding io-uring feature # tests avoiding io-uring feature
ci-test = " hack --feature-powerset --exclude=actix-rt --exclude=actix-server --exclude-features=io-uring test --workspace --lib --tests --no-fail-fast -- --nocapture" ci-test = "hack --feature-powerset --exclude-features=io-uring test --lib --tests --no-fail-fast -- --nocapture"
ci-test-rt = " hack --feature-powerset --exclude-features=io-uring test --package=actix-rt --lib --tests --no-fail-fast -- --nocapture"
ci-test-server = "hack --feature-powerset --exclude-features=io-uring test --package=actix-server --lib --tests --no-fail-fast -- --nocapture" # tests avoiding io-uring feature on Windows
ci-test-win = "hack --feature-powerset --depth 2 --exclude-features=io-uring test --lib --tests --no-fail-fast -- --nocapture"
# test with io-uring feature # test with io-uring feature
ci-test-rt-linux = " hack --feature-powerset test --package=actix-rt --lib --tests --no-fail-fast -- --nocapture" ci-test-linux = "hack --feature-powerset test --lib --tests --no-fail-fast -- --nocapture"
ci-test-server-linux = "hack --feature-powerset test --package=actix-server --lib --tests --no-fail-fast -- --nocapture"
# test lower msrv
ci-test-lower-msrv = "hack --workspace --exclude=actix-server --exclude=actix-tls --feature-powerset test --lib --tests --no-fail-fast -- --nocapture"

View File

@@ -101,14 +101,11 @@ jobs:
if: > if: >
matrix.target.os != 'ubuntu-latest' matrix.target.os != 'ubuntu-latest'
&& matrix.target.triple != 'x86_64-pc-windows-gnu' && matrix.target.triple != 'x86_64-pc-windows-gnu'
run: | run: cargo ci-test
cargo ci-test
cargo ci-test-rt
cargo ci-test-server
- name: tests - name: tests
if: matrix.target.os == 'ubuntu-latest' if: matrix.target.os == 'ubuntu-latest'
run: | run: |
sudo bash -c "ulimit -Sl 512 && ulimit -Hl 512 && PATH=$PATH:/usr/share/rust/.cargo/bin && RUSTUP_TOOLCHAIN=${{ matrix.version }} cargo ci-test && RUSTUP_TOOLCHAIN=${{ matrix.version }} cargo ci-test-rt-linux && RUSTUP_TOOLCHAIN=${{ matrix.version }} cargo ci-test-server-linux" sudo bash -c "ulimit -Sl 512 && ulimit -Hl 512 && PATH=$PATH:/usr/share/rust/.cargo/bin && RUSTUP_TOOLCHAIN=${{ matrix.version }} cargo ci-test && RUSTUP_TOOLCHAIN=${{ matrix.version }} cargo ci-test-linux"
- name: Clear the cargo caches - name: Clear the cargo caches
run: | run: |

View File

@@ -18,7 +18,7 @@ jobs:
- { name: Windows (MinGW), os: windows-latest, triple: x86_64-pc-windows-gnu } - { name: Windows (MinGW), os: windows-latest, triple: x86_64-pc-windows-gnu }
- { name: Windows (32-bit), os: windows-latest, triple: i686-pc-windows-msvc } - { name: Windows (32-bit), os: windows-latest, triple: i686-pc-windows-msvc }
version: version:
- 1.52.0 # MSRV for -server and -tls - 1.57.0
- stable - stable
name: ${{ matrix.target.name }} / ${{ matrix.version }} name: ${{ matrix.target.name }} / ${{ matrix.version }}
@@ -73,6 +73,15 @@ jobs:
command: install command: install
args: cargo-hack args: cargo-hack
- name: Generate Cargo.lock
uses: actions-rs/cargo@v1
with: { command: generate-lockfile }
- name: workaround MSRV issues
if: matrix.version != 'stable'
run: |
cargo update -p=time --precise=0.3.13 # time is only a dev dep so shouldn't affect msrv
- name: check lib - name: check lib
if: > if: >
matrix.target.os != 'ubuntu-latest' matrix.target.os != 'ubuntu-latest'
@@ -100,58 +109,21 @@ jobs:
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
with: { command: ci-check-linux } with: { command: ci-check-linux }
- name: tests
if: matrix.target.os == 'macos-latest'
run: cargo ci-test
- name: tests - name: tests
if: > if: >
matrix.target.os != 'ubuntu-latest' matrix.target.os == 'windows-latest'
&& matrix.target.triple != 'x86_64-pc-windows-gnu' && matrix.target.triple != 'x86_64-pc-windows-gnu'
run: | run: cargo ci-test-win
cargo ci-test
cargo ci-test-rt
cargo ci-test-server
- name: tests - name: tests
if: matrix.target.os == 'ubuntu-latest' if: matrix.target.os == 'ubuntu-latest'
run: | run: |
sudo bash -c "ulimit -Sl 512 && ulimit -Hl 512 && PATH=$PATH:/usr/share/rust/.cargo/bin && RUSTUP_TOOLCHAIN=${{ matrix.version }} cargo ci-test && RUSTUP_TOOLCHAIN=${{ matrix.version }} cargo ci-test-rt-linux && RUSTUP_TOOLCHAIN=${{ matrix.version }} cargo ci-test-server-linux" sudo bash -c "ulimit -Sl 512 && ulimit -Hl 512 && PATH=$PATH:/usr/share/rust/.cargo/bin && RUSTUP_TOOLCHAIN=${{ matrix.version }} cargo ci-test && RUSTUP_TOOLCHAIN=${{ matrix.version }} cargo ci-test-linux"
- name: Clear the cargo caches
run: |
cargo install cargo-cache --version 0.6.2 --no-default-features --features ci-autoclean
cargo-cache
build_and_test_lower_msrv:
name: Linux / 1.49 (lower MSRV)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Install 1.49.0 # MSRV for all but -server and -tls
uses: actions-rs/toolchain@v1
with:
toolchain: 1.49.0-x86_64-unknown-linux-gnu
profile: minimal
override: true
- name: Install cargo-hack
uses: actions-rs/cargo@v1
with:
command: install
args: cargo-hack
- name: Generate Cargo.lock
uses: actions-rs/cargo@v1
with: { command: generate-lockfile }
- name: Tweak lockfile
uses: actions-rs/cargo@v1
with:
command: update
args: -p=rustls --precise=0.20.2
- name: tests
run: |
sudo bash -c "ulimit -Sl 512 && ulimit -Hl 512 && PATH=$PATH:/usr/share/rust/.cargo/bin && RUSTUP_TOOLCHAIN=1.49 cargo ci-test-lower-msrv"
- name: Clear the cargo caches - name: Clear the cargo caches
if: matrix.version == 'stable' # MSRV(1.58) cargo-cache now fails to install on 1.57
run: | run: |
cargo install cargo-cache --version 0.6.2 --no-default-features --features ci-autoclean cargo install cargo-cache --version 0.6.2 --no-default-features --features ci-autoclean
cargo-cache cargo-cache

View File

@@ -1,6 +1,7 @@
# Changes # Changes
## Unreleased - 2022-xx-xx ## Unreleased - 2022-xx-xx
- Minimum supported Rust version (MSRV) is now 1.57.
## 0.5.1 - 2022-03-15 ## 0.5.1 - 2022-03-15

View File

@@ -28,7 +28,7 @@ tokio-util = { version = "0.7", features = ["codec", "io"] }
tracing = { version = "0.1.30", default-features = false, features = ["log"] } tracing = { version = "0.1.30", default-features = false, features = ["log"] }
[dev-dependencies] [dev-dependencies]
criterion = { version = "0.3", features = ["html_reports"] } criterion = { version = "0.4", features = ["html_reports"] }
tokio-test = "0.4.2" tokio-test = "0.4.2"
[[bench]] [[bench]]

View File

@@ -1,8 +1,7 @@
//! Codec utilities for working with framed protocols. //! Codec utilities for working with framed protocols.
//! //!
//! Contains adapters to go from streams of bytes, [`AsyncRead`] and //! Contains adapters to go from streams of bytes, [`AsyncRead`] and [`AsyncWrite`], to framed
//! [`AsyncWrite`], to framed streams implementing [`Sink`] and [`Stream`]. //! streams implementing [`Sink`] and [`Stream`]. Framed streams are also known as `transports`.
//! Framed streams are also known as `transports`.
//! //!
//! [`Sink`]: futures_sink::Sink //! [`Sink`]: futures_sink::Sink
//! [`Stream`]: futures_core::Stream //! [`Stream`]: futures_core::Stream
@@ -16,10 +15,10 @@ mod bcodec;
mod framed; mod framed;
mod lines; mod lines;
pub use self::bcodec::BytesCodec;
pub use self::framed::{Framed, FramedParts};
pub use self::lines::LinesCodec;
pub use tokio::io::{AsyncRead, AsyncWrite, ReadBuf}; pub use tokio::io::{AsyncRead, AsyncWrite, ReadBuf};
pub use tokio_util::codec::{Decoder, Encoder}; pub use tokio_util::codec::{Decoder, Encoder};
pub use tokio_util::io::poll_read_buf; pub use tokio_util::io::poll_read_buf;
pub use self::bcodec::BytesCodec;
pub use self::framed::{Framed, FramedParts};
pub use self::lines::LinesCodec;

View File

@@ -1,12 +1,16 @@
use std::{
collections::VecDeque,
io::{self, Write},
pin::Pin,
task::{
Context,
Poll::{self, Pending, Ready},
},
};
use actix_codec::*; use actix_codec::*;
use bytes::Buf; use bytes::{Buf as _, BufMut as _, BytesMut};
use bytes::{BufMut, BytesMut};
use futures_sink::Sink; use futures_sink::Sink;
use std::collections::VecDeque;
use std::io::{self, Write};
use std::pin::Pin;
use std::task::Poll::{Pending, Ready};
use std::task::{Context, Poll};
use tokio_test::{assert_ready, task}; use tokio_test::{assert_ready, task};
macro_rules! bilateral { macro_rules! bilateral {

View File

@@ -1,7 +1,7 @@
# Changes # Changes
## Unreleased - 2022-xx-xx ## Unreleased - 2022-xx-xx
- Minimum supported Rust version (MSRV) is now 1.49. - Minimum supported Rust version (MSRV) is now 1.57.
## 0.2.3 - 2021-10-19 ## 0.2.3 - 2021-10-19

View File

@@ -1,6 +1,10 @@
# Changes # Changes
## Unreleased - 2022-xx-xx ## Unreleased - 2022-xx-xx
- Add `#[track_caller]` attribute to `spawn` functions and methods. [#454]
- Minimum supported Rust version (MSRV) is now 1.57.
[#454]: https://github.com/actix/actix-net/pull/454
## 2.7.0 - 2022-03-08 ## 2.7.0 - 2022-03-08

View File

@@ -4,7 +4,6 @@ version = "2.7.0"
authors = [ authors = [
"Nikolay Kim <fafhrd91@gmail.com>", "Nikolay Kim <fafhrd91@gmail.com>",
"Rob Ede <robjtede@icloud.com>", "Rob Ede <robjtede@icloud.com>",
"fakeshadow <24548779@qq.com>",
] ]
description = "Tokio-based single-threaded async runtime for the Actix ecosystem" description = "Tokio-based single-threaded async runtime for the Actix ecosystem"
keywords = ["async", "futures", "io", "runtime"] keywords = ["async", "futures", "io", "runtime"]

View File

@@ -1,7 +1,9 @@
use hyper::service::{make_service_fn, service_fn}; use std::{convert::Infallible, net::SocketAddr};
use hyper::{Body, Request, Response, Server};
use std::convert::Infallible; use hyper::{
use std::net::SocketAddr; service::{make_service_fn, service_fn},
Body, Request, Response, Server,
};
async fn handle(_req: Request<Body>) -> Result<Response<Body>, Infallible> { async fn handle(_req: Request<Body>) -> Result<Response<Body>, Infallible> {
Ok(Response::new(Body::from("Hello World"))) Ok(Response::new(Body::from("Hello World")))

View File

@@ -260,6 +260,7 @@ impl Arbiter {
/// If you require a result, include a response channel in the future. /// If you require a result, include a response channel in the future.
/// ///
/// Returns true if future was sent successfully and false if the Arbiter has died. /// Returns true if future was sent successfully and false if the Arbiter has died.
#[track_caller]
pub fn spawn<Fut>(&self, future: Fut) -> bool pub fn spawn<Fut>(&self, future: Fut) -> bool
where where
Fut: Future<Output = ()> + Send + 'static, Fut: Future<Output = ()> + Send + 'static,
@@ -275,6 +276,7 @@ impl Arbiter {
/// channel in the function. /// channel in the function.
/// ///
/// Returns true if function was sent successfully and false if the Arbiter has died. /// Returns true if function was sent successfully and false if the Arbiter has died.
#[track_caller]
pub fn spawn_fn<F>(&self, f: F) -> bool pub fn spawn_fn<F>(&self, f: F) -> bool
where where
F: FnOnce() + Send + 'static, F: FnOnce() + Send + 'static,

View File

@@ -51,13 +51,10 @@ compile_error!("io_uring is a linux only feature.");
use std::future::Future; use std::future::Future;
use tokio::task::JoinHandle;
// Cannot define a main macro when compiled into test harness. // Cannot define a main macro when compiled into test harness.
// Workaround for https://github.com/rust-lang/rust/issues/62127. // Workaround for https://github.com/rust-lang/rust/issues/62127.
#[cfg(all(feature = "macros", not(test)))] #[cfg(all(feature = "macros", not(test)))]
pub use actix_macros::main; pub use actix_macros::main;
#[cfg(feature = "macros")] #[cfg(feature = "macros")]
pub use actix_macros::test; pub use actix_macros::test;
@@ -65,12 +62,13 @@ mod arbiter;
mod runtime; mod runtime;
mod system; mod system;
pub use tokio::pin;
use tokio::task::JoinHandle;
pub use self::arbiter::{Arbiter, ArbiterHandle}; pub use self::arbiter::{Arbiter, ArbiterHandle};
pub use self::runtime::Runtime; pub use self::runtime::Runtime;
pub use self::system::{System, SystemRunner}; pub use self::system::{System, SystemRunner};
pub use tokio::pin;
pub mod signal { pub mod signal {
//! Asynchronous signal handling (Tokio re-exports). //! Asynchronous signal handling (Tokio re-exports).
@@ -95,7 +93,6 @@ pub mod net {
use tokio::io::{AsyncRead, AsyncWrite, Interest}; use tokio::io::{AsyncRead, AsyncWrite, Interest};
pub use tokio::net::UdpSocket; pub use tokio::net::UdpSocket;
pub use tokio::net::{TcpListener, TcpSocket, TcpStream}; pub use tokio::net::{TcpListener, TcpSocket, TcpStream};
#[cfg(unix)] #[cfg(unix)]
pub use tokio::net::{UnixDatagram, UnixListener, UnixStream}; pub use tokio::net::{UnixDatagram, UnixListener, UnixStream};
@@ -198,6 +195,7 @@ pub mod task {
/// assert!(handle.await.unwrap_err().is_cancelled()); /// assert!(handle.await.unwrap_err().is_cancelled());
/// # }); /// # });
/// ``` /// ```
#[track_caller]
#[inline] #[inline]
pub fn spawn<Fut>(f: Fut) -> JoinHandle<Fut::Output> pub fn spawn<Fut>(f: Fut) -> JoinHandle<Fut::Output>
where where

View File

@@ -53,6 +53,7 @@ impl Runtime {
/// # Panics /// # Panics
/// This function panics if the spawn fails. Failure occurs if the executor is currently at /// This function panics if the spawn fails. Failure occurs if the executor is currently at
/// capacity and is unable to spawn a new future. /// capacity and is unable to spawn a new future.
#[track_caller]
pub fn spawn<F>(&self, future: F) -> JoinHandle<F::Output> pub fn spawn<F>(&self, future: F) -> JoinHandle<F::Output>
where where
F: Future + 'static, F: Future + 'static,
@@ -73,6 +74,7 @@ impl Runtime {
/// ///
/// The caller is responsible for ensuring that other spawned futures complete execution by /// The caller is responsible for ensuring that other spawned futures complete execution by
/// calling `block_on` or `run`. /// calling `block_on` or `run`.
#[track_caller]
pub fn block_on<F>(&self, f: F) -> F::Output pub fn block_on<F>(&self, f: F) -> F::Output
where where
F: Future, F: Future,

View File

@@ -204,6 +204,7 @@ impl SystemRunner {
} }
/// Runs the provided future, blocking the current thread until the future completes. /// Runs the provided future, blocking the current thread until the future completes.
#[track_caller]
#[inline] #[inline]
pub fn block_on<F: Future>(&self, fut: F) -> F::Output { pub fn block_on<F: Future>(&self, fut: F) -> F::Output {
self.rt.block_on(fut) self.rt.block_on(fut)

View File

@@ -4,7 +4,6 @@ use std::{
}; };
use actix_rt::{task::JoinError, Arbiter, System}; use actix_rt::{task::JoinError, Arbiter, System};
#[cfg(not(feature = "io-uring"))] #[cfg(not(feature = "io-uring"))]
use { use {
std::{sync::mpsc::channel, thread}, std::{sync::mpsc::channel, thread},

View File

@@ -1,6 +1,7 @@
# Changes # Changes
## Unreleased - 2022-xx-xx ## Unreleased - 2022-xx-xx
- Minimum supported Rust version (MSRV) is now 1.57.
## 2.1.1 - 2022-03-09 ## 2.1.1 - 2022-03-09

View File

@@ -3,7 +3,6 @@ name = "actix-server"
version = "2.1.1" version = "2.1.1"
authors = [ authors = [
"Nikolay Kim <fafhrd91@gmail.com>", "Nikolay Kim <fafhrd91@gmail.com>",
"fakeshadow <24548779@qq.com>",
"Rob Ede <robjtede@icloud.com>", "Rob Ede <robjtede@icloud.com>",
"Ali MJ Al-Nasrawy <alimjalnasrawy@gmail.com>", "Ali MJ Al-Nasrawy <alimjalnasrawy@gmail.com>",
] ]
@@ -41,8 +40,8 @@ tracing = { version = "0.1.30", default-features = false, features = ["log"] }
tokio-uring = { version = "0.3", optional = true } tokio-uring = { version = "0.3", optional = true }
[dev-dependencies] [dev-dependencies]
actix-codec = "0.5.0" actix-codec = "0.5"
actix-rt = "2.6.0" actix-rt = "2.6"
bytes = "1" bytes = "1"
env_logger = "0.9" env_logger = "0.9"

View File

@@ -74,7 +74,7 @@ async fn run() -> io::Result<()> {
// close connection after file has been copied to TCP stream // close connection after file has been copied to TCP stream
Ok(()) Ok(())
}) })
.map_err(|err| tracing::error!("Service Error: {:?}", err)) .map_err(|err| tracing::error!("service error: {:?}", err))
})? })?
.workers(2) .workers(2)
.run() .run()

View File

@@ -64,7 +64,7 @@ async fn run() -> io::Result<()> {
// stream error; bail from loop with error // stream error; bail from loop with error
Err(err) => { Err(err) => {
tracing::error!("Stream Error: {:?}", err); tracing::error!("stream error: {:?}", err);
return Err(()); return Err(());
} }
} }
@@ -74,7 +74,7 @@ async fn run() -> io::Result<()> {
Ok((buf.freeze(), size)) Ok((buf.freeze(), size))
} }
}) })
.map_err(|err| tracing::error!("Service Error: {:?}", err)) .map_err(|err| tracing::error!("service error: {:?}", err))
.and_then(move |(_, size)| { .and_then(move |(_, size)| {
let num = num2.load(Ordering::SeqCst); let num = num2.load(Ordering::SeqCst);
tracing::info!("[{}] total bytes read: {}", num, size); tracing::info!("[{}] total bytes read: {}", num, size);

View File

@@ -24,7 +24,7 @@ struct ServerSocketInfo {
timeout: Option<actix_rt::time::Instant>, timeout: Option<actix_rt::time::Instant>,
} }
/// poll instance of the server. /// Poll instance of the server.
pub(crate) struct Accept { pub(crate) struct Accept {
poll: Poll, poll: Poll,
waker_queue: WakerQueue, waker_queue: WakerQueue,
@@ -140,7 +140,7 @@ impl Accept {
WAKER_TOKEN => { WAKER_TOKEN => {
let exit = self.handle_waker(sockets); let exit = self.handle_waker(sockets);
if exit { if exit {
info!("Accept thread stopped"); info!("accept thread stopped");
return; return;
} }
} }
@@ -161,11 +161,13 @@ impl Accept {
// a loop that would try to drain the command channel. It's yet unknown // a loop that would try to drain the command channel. It's yet unknown
// if it's necessary/good practice to actively drain the waker queue. // if it's necessary/good practice to actively drain the waker queue.
loop { loop {
// take guard with every iteration so no new interest can be added // Take guard with every iteration so no new interests can be added until the current
// until the current task is done. // task is done. Take care not to take the guard again inside this loop.
let mut guard = self.waker_queue.guard(); let mut guard = self.waker_queue.guard();
#[allow(clippy::significant_drop_in_scrutinee)]
match guard.pop_front() { match guard.pop_front() {
// worker notify it becomes available. // Worker notified it became available.
Some(WakerInterest::WorkerAvailable(idx)) => { Some(WakerInterest::WorkerAvailable(idx)) => {
drop(guard); drop(guard);
@@ -176,7 +178,7 @@ impl Accept {
} }
} }
// a new worker thread is made and it's handle would be added to Accept // A new worker thread has been created so store its handle.
Some(WakerInterest::Worker(handle)) => { Some(WakerInterest::Worker(handle)) => {
drop(guard); drop(guard);
@@ -297,16 +299,16 @@ impl Accept {
fn register_logged(&self, info: &mut ServerSocketInfo) { fn register_logged(&self, info: &mut ServerSocketInfo) {
match self.register(info) { match self.register(info) {
Ok(_) => debug!("Resume accepting connections on {}", info.lst.local_addr()), Ok(_) => debug!("resume accepting connections on {}", info.lst.local_addr()),
Err(err) => error!("Can not register server socket {}", err), Err(err) => error!("can not register server socket {}", err),
} }
} }
fn deregister_logged(&self, info: &mut ServerSocketInfo) { fn deregister_logged(&self, info: &mut ServerSocketInfo) {
match self.poll.registry().deregister(&mut info.lst) { match self.poll.registry().deregister(&mut info.lst) {
Ok(_) => debug!("Paused accepting connections on {}", info.lst.local_addr()), Ok(_) => debug!("paused accepting connections on {}", info.lst.local_addr()),
Err(err) => { Err(err) => {
error!("Can not deregister server socket {}", err) error!("can not deregister server socket {}", err)
} }
} }
} }
@@ -350,7 +352,7 @@ impl Accept {
self.remove_next(); self.remove_next();
if self.handles.is_empty() { if self.handles.is_empty() {
error!("No workers"); error!("no workers");
// All workers are gone and Conn is nowhere to be sent. // All workers are gone and Conn is nowhere to be sent.
// Treat this situation as Ok and drop Conn. // Treat this situation as Ok and drop Conn.
return Ok(()); return Ok(());
@@ -399,7 +401,7 @@ impl Accept {
Err(ref err) if err.kind() == io::ErrorKind::WouldBlock => return, Err(ref err) if err.kind() == io::ErrorKind::WouldBlock => return,
Err(ref err) if connection_error(err) => continue, Err(ref err) if connection_error(err) => continue,
Err(err) => { Err(err) => {
error!("Error accepting connection: {}", err); error!("error accepting connection: {}", err);
// deregister listener temporary // deregister listener temporary
self.deregister_logged(info); self.deregister_logged(info);

View File

@@ -197,7 +197,7 @@ impl ServerBuilder {
if self.sockets.is_empty() { if self.sockets.is_empty() {
panic!("Server should have at least one bound socket"); panic!("Server should have at least one bound socket");
} else { } else {
info!("Starting {} workers", self.threads); info!("starting {} workers", self.threads);
Server::new(self) Server::new(self)
} }
} }

View File

@@ -63,10 +63,10 @@ impl<T> Future for JoinAll<T> {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*;
use actix_utils::future::ready; use actix_utils::future::ready;
use super::*;
#[actix_rt::test] #[actix_rt::test]
async fn test_join_all() { async fn test_join_all() {
let futs = vec![ready(Ok(1)), ready(Err(3)), ready(Ok(9))]; let futs = vec![ready(Ok(1)), ready(Err(3)), ready(Ok(9))];

View File

@@ -22,10 +22,9 @@ pub use self::builder::ServerBuilder;
pub use self::handle::ServerHandle; pub use self::handle::ServerHandle;
pub use self::server::Server; pub use self::server::Server;
pub use self::service::ServerServiceFactory; pub use self::service::ServerServiceFactory;
pub use self::test_server::TestServer;
#[doc(hidden)] #[doc(hidden)]
pub use self::socket::FromStream; pub use self::socket::FromStream;
pub use self::test_server::TestServer;
/// Start server building process /// Start server building process
#[doc(hidden)] #[doc(hidden)]

View File

@@ -66,7 +66,7 @@ pub(crate) enum ServerCommand {
/// server has fully shut down. /// server has fully shut down.
/// ///
/// # Shutdown Signals /// # Shutdown Signals
/// On UNIX systems, `SIGQUIT` will start a graceful shutdown and `SIGTERM` or `SIGINT` will start a /// On UNIX systems, `SIGTERM` will start a graceful shutdown and `SIGQUIT` or `SIGINT` will start a
/// forced shutdown. On Windows, a Ctrl-C signal will start a forced shutdown. /// forced shutdown. On Windows, a Ctrl-C signal will start a forced shutdown.
/// ///
/// A graceful shutdown will wait for all workers to stop first. /// A graceful shutdown will wait for all workers to stop first.
@@ -200,7 +200,7 @@ impl ServerInner {
for (_, name, lst) in &builder.sockets { for (_, name, lst) in &builder.sockets {
info!( info!(
r#"Starting service: "{}", workers: {}, listening on: {}"#, r#"starting service: "{}", workers: {}, listening on: {}"#,
name, name,
builder.threads, builder.threads,
lst.local_addr() lst.local_addr()
@@ -283,7 +283,7 @@ impl ServerInner {
// TODO: maybe just return with warning log if not found ? // TODO: maybe just return with warning log if not found ?
assert!(self.worker_handles.iter().any(|wrk| wrk.idx == idx)); assert!(self.worker_handles.iter().any(|wrk| wrk.idx == idx));
error!("Worker {} has died; restarting", idx); error!("worker {} has died; restarting", idx);
let factories = self let factories = self
.services .services

View File

@@ -78,7 +78,7 @@ where
Ok(()) Ok(())
} }
Err(err) => { Err(err) => {
error!("Can not convert to an async tcp stream: {}", err); error!("can not convert to an async TCP stream: {}", err);
Err(()) Err(())
} }
}) })

View File

@@ -70,7 +70,7 @@ impl Signals {
.map(|tokio_sig| (*sig, tokio_sig)) .map(|tokio_sig| (*sig, tokio_sig))
.map_err(|e| { .map_err(|e| {
tracing::error!( tracing::error!(
"Can not initialize stream handler for {:?} err: {}", "can not initialize stream handler for {:?} err: {}",
sig, sig,
e e
) )

View File

@@ -6,7 +6,6 @@ use std::{fmt, io};
use actix_rt::net::TcpStream; use actix_rt::net::TcpStream;
pub(crate) use mio::net::TcpListener as MioTcpListener; pub(crate) use mio::net::TcpListener as MioTcpListener;
use mio::{event::Source, Interest, Registry, Token}; use mio::{event::Source, Interest, Registry, Token};
#[cfg(unix)] #[cfg(unix)]
pub(crate) use { pub(crate) use {
mio::net::UnixListener as MioUnixListener, mio::net::UnixListener as MioUnixListener,

View File

@@ -337,7 +337,7 @@ impl ServerWorker {
Ok((token, svc)) => services.push((idx, token, svc)), Ok((token, svc)) => services.push((idx, token, svc)),
Err(err) => { Err(err) => {
error!("Can not start worker: {:?}", err); error!("can not start worker: {:?}", err);
return Err(io::Error::new( return Err(io::Error::new(
io::ErrorKind::Other, io::ErrorKind::Other,
format!("can not start server service {}", idx), format!("can not start server service {}", idx),
@@ -436,7 +436,7 @@ impl ServerWorker {
Ok((token, svc)) => services.push((idx, token, svc)), Ok((token, svc)) => services.push((idx, token, svc)),
Err(err) => { Err(err) => {
error!("Can not start worker: {:?}", err); error!("can not start worker: {:?}", err);
Arbiter::current().stop(); Arbiter::current().stop();
factory_tx factory_tx
.send(Err(io::Error::new( .send(Err(io::Error::new(
@@ -476,7 +476,7 @@ impl ServerWorker {
fn restart_service(&mut self, idx: usize, factory_id: usize) { fn restart_service(&mut self, idx: usize, factory_id: usize) {
let factory = &self.factories[factory_id]; let factory = &self.factories[factory_id];
trace!("Service {:?} failed, restarting", factory.name(idx)); trace!("service {:?} failed, restarting", factory.name(idx));
self.services[idx].status = WorkerServiceStatus::Restarting; self.services[idx].status = WorkerServiceStatus::Restarting;
self.state = WorkerState::Restarting(Restart { self.state = WorkerState::Restarting(Restart {
factory_id, factory_id,
@@ -508,7 +508,7 @@ impl ServerWorker {
Poll::Ready(Ok(_)) => { Poll::Ready(Ok(_)) => {
if srv.status == WorkerServiceStatus::Unavailable { if srv.status == WorkerServiceStatus::Unavailable {
trace!( trace!(
"Service {:?} is available", "service {:?} is available",
self.factories[srv.factory_idx].name(idx) self.factories[srv.factory_idx].name(idx)
); );
srv.status = WorkerServiceStatus::Available; srv.status = WorkerServiceStatus::Available;
@@ -519,7 +519,7 @@ impl ServerWorker {
if srv.status == WorkerServiceStatus::Available { if srv.status == WorkerServiceStatus::Available {
trace!( trace!(
"Service {:?} is unavailable", "service {:?} is unavailable",
self.factories[srv.factory_idx].name(idx) self.factories[srv.factory_idx].name(idx)
); );
srv.status = WorkerServiceStatus::Unavailable; srv.status = WorkerServiceStatus::Unavailable;
@@ -527,7 +527,7 @@ impl ServerWorker {
} }
Poll::Ready(Err(_)) => { Poll::Ready(Err(_)) => {
error!( error!(
"Service {:?} readiness check returned error, restarting", "service {:?} readiness check returned error, restarting",
self.factories[srv.factory_idx].name(idx) self.factories[srv.factory_idx].name(idx)
); );
srv.status = WorkerServiceStatus::Failed; srv.status = WorkerServiceStatus::Failed;
@@ -590,11 +590,11 @@ impl Future for ServerWorker {
{ {
let num = this.counter.total(); let num = this.counter.total();
if num == 0 { if num == 0 {
info!("Shutting down idle worker"); info!("shutting down idle worker");
let _ = tx.send(true); let _ = tx.send(true);
return Poll::Ready(()); return Poll::Ready(());
} else if graceful { } else if graceful {
info!("Graceful worker shutdown; finishing {} connections", num); info!("graceful worker shutdown; finishing {} connections", num);
this.shutdown(false); this.shutdown(false);
this.state = WorkerState::Shutdown(Shutdown { this.state = WorkerState::Shutdown(Shutdown {
@@ -603,7 +603,7 @@ impl Future for ServerWorker {
tx, tx,
}); });
} else { } else {
info!("Force shutdown worker, closing {} connections", num); info!("force shutdown worker, closing {} connections", num);
this.shutdown(true); this.shutdown(true);
let _ = tx.send(false); let _ = tx.send(false);
@@ -638,7 +638,7 @@ impl Future for ServerWorker {
assert_eq!(token, token_new); assert_eq!(token, token_new);
trace!( trace!(
"Service {:?} has been restarted", "service {:?} has been restarted",
this.factories[factory_id].name(token) this.factories[factory_id].name(token)
); );
@@ -685,7 +685,7 @@ impl Future for ServerWorker {
match this.check_readiness(cx) { match this.check_readiness(cx) {
Ok(true) => {} Ok(true) => {}
Ok(false) => { Ok(false) => {
trace!("Worker is unavailable"); trace!("worker is unavailable");
this.state = WorkerState::Unavailable; this.state = WorkerState::Unavailable;
return self.poll(cx); return self.poll(cx);
} }

View File

@@ -186,9 +186,9 @@ fn test_start() {
#[actix_rt::test] #[actix_rt::test]
async fn test_max_concurrent_connections() { async fn test_max_concurrent_connections() {
// Note: // Note:
// A tcp listener would accept connects based on it's backlog setting. // A TCP listener would accept connects based on it's backlog setting.
// //
// The limit test on the other hand is only for concurrent tcp stream limiting a work // The limit test on the other hand is only for concurrent TCP stream limiting a work
// thread accept. // thread accept.
use tokio::io::AsyncWriteExt; use tokio::io::AsyncWriteExt;

View File

@@ -1,7 +1,7 @@
# Changes # Changes
## Unreleased - 2022-xx-xx ## Unreleased - 2022-xx-xx
- Minimum supported Rust version (MSRV) is now 1.49. - Minimum supported Rust version (MSRV) is now 1.57.
## 2.0.2 - 2021-12-18 ## 2.0.2 - 2021-12-18

View File

@@ -4,7 +4,6 @@ version = "2.0.2"
authors = [ authors = [
"Nikolay Kim <fafhrd91@gmail.com>", "Nikolay Kim <fafhrd91@gmail.com>",
"Rob Ede <robjtede@icloud.com>", "Rob Ede <robjtede@icloud.com>",
"fakeshadow <24548779@qq.com>",
] ]
description = "Service trait and combinators for representing asynchronous request/response operations." description = "Service trait and combinators for representing asynchronous request/response operations."
keywords = ["network", "framework", "async", "futures", "service"] keywords = ["network", "framework", "async", "futures", "service"]
@@ -23,6 +22,6 @@ paste = "1"
pin-project-lite = "0.2" pin-project-lite = "0.2"
[dev-dependencies] [dev-dependencies]
actix-rt = "2.0.0" actix-rt = "2"
actix-utils = "3.0.0" actix-utils = "3"
futures-util = { version = "0.3.7", default-features = false } futures-util = { version = "0.3.7", default-features = false }

View File

@@ -394,9 +394,10 @@ mod tests {
#[actix_rt::test] #[actix_rt::test]
async fn test_auto_impl_send() { async fn test_auto_impl_send() {
use crate::{map_config, ServiceExt, ServiceFactoryExt};
use alloc::rc::Rc; use alloc::rc::Rc;
use crate::{map_config, ServiceExt, ServiceFactoryExt};
let srv_1 = fn_service(|_: Rc<u8>| ok::<_, Rc<u8>>(Rc::new(0u8))); let srv_1 = fn_service(|_: Rc<u8>| ok::<_, Rc<u8>>(Rc::new(0u8)));
let fac_1 = fn_factory_with_config(|_: Rc<u8>| { let fac_1 = fn_factory_with_config(|_: Rc<u8>| {

View File

@@ -38,10 +38,9 @@ pub use self::apply_cfg::{apply_cfg, apply_cfg_factory};
pub use self::ext::{ServiceExt, ServiceFactoryExt, TransformExt}; pub use self::ext::{ServiceExt, ServiceFactoryExt, TransformExt};
pub use self::fn_service::{fn_factory, fn_factory_with_config, fn_service}; pub use self::fn_service::{fn_factory, fn_factory_with_config, fn_service};
pub use self::map_config::{map_config, unit_config}; pub use self::map_config::{map_config, unit_config};
pub use self::transform::{apply, ApplyTransform, Transform};
#[allow(unused_imports)] #[allow(unused_imports)]
use self::ready::{err, ok, ready, Ready}; use self::ready::{err, ok, ready, Ready};
pub use self::transform::{apply, ApplyTransform, Transform};
/// An asynchronous operation from `Request` to a `Response`. /// An asynchronous operation from `Request` to a `Response`.
/// ///

View File

@@ -25,6 +25,8 @@
/// } /// }
/// } /// }
/// ``` /// ```
///
/// [`forward_ready!`]: crate::forward_ready
#[macro_export] #[macro_export]
macro_rules! always_ready { macro_rules! always_ready {
() => { () => {

View File

@@ -1,6 +1,7 @@
# Changes # Changes
## Unreleased - 2022-xx-xx ## Unreleased - 2022-xx-xx
- Minimum supported Rust version (MSRV) is now 1.57.
## 3.0.4 - 2022-03-15 ## 3.0.4 - 2022-03-15

View File

@@ -42,13 +42,14 @@ native-tls = ["tokio-native-tls"]
uri = ["http"] uri = ["http"]
[dependencies] [dependencies]
actix-codec = "0.5.0"
actix-rt = { version = "2.2.0", default-features = false } actix-rt = { version = "2.2.0", default-features = false }
actix-service = "2.0.0" actix-service = "2"
actix-utils = "3.0.0" actix-utils = "3"
futures-core = { version = "0.3.7", default-features = false, features = ["alloc"] } futures-core = { version = "0.3.7", default-features = false, features = ["alloc"] }
impl-more = "0.1"
pin-project-lite = "0.2.7" pin-project-lite = "0.2.7"
tokio = "1.13.1"
tokio-util = "0.7" tokio-util = "0.7"
tracing = { version = "0.1.30", default-features = false, features = ["log"] } tracing = { version = "0.1.30", default-features = false, features = ["log"] }
@@ -67,16 +68,17 @@ webpki-roots = { version = "0.22", optional = true }
tokio-native-tls = { version = "0.3", optional = true } tokio-native-tls = { version = "0.3", optional = true }
[dev-dependencies] [dev-dependencies]
actix-rt = "2.2.0" actix-codec = "0.5"
actix-server = "2.0.0" actix-rt = "2.2"
actix-server = "2"
bytes = "1" bytes = "1"
env_logger = "0.9" env_logger = "0.9"
futures-util = { version = "0.3.7", default-features = false, features = ["sink"] } futures-util = { version = "0.3.7", default-features = false, features = ["sink"] }
log = "0.4" log = "0.4"
rcgen = "0.8" rcgen = "0.10"
rustls-pemfile = "0.2.1" rustls-pemfile = "1"
tokio-rustls = { version = "0.23", features = ["dangerous_configuration"] } tokio-rustls = { version = "0.23", features = ["dangerous_configuration"] }
trust-dns-resolver = "0.20.0" trust-dns-resolver = "0.22"
[[example]] [[example]]
name = "accept-rustls" name = "accept-rustls"

View File

@@ -15,8 +15,9 @@
//! http --verify=false https://127.0.0.1:8443 //! http --verify=false https://127.0.0.1:8443
//! ``` //! ```
// this use only exists because of how we have organised the crate #[rustfmt::skip]
// it is not necessary for your actual code // this `use` is only exists because of how we have organised the crate
// it is not necessary for your actual code; you should import from `rustls` directly
use tokio_rustls::rustls; use tokio_rustls::rustls;
use std::{ use std::{

View File

@@ -10,7 +10,6 @@ use std::{
time::Duration, time::Duration,
}; };
use actix_codec::{AsyncRead, AsyncWrite, ReadBuf};
use actix_rt::{ use actix_rt::{
net::{ActixStream, Ready}, net::{ActixStream, Ready},
time::timeout, time::timeout,
@@ -21,10 +20,10 @@ use actix_utils::{
future::{ready, Ready as FutReady}, future::{ready, Ready as FutReady},
}; };
use futures_core::future::LocalBoxFuture; use futures_core::future::LocalBoxFuture;
use tokio::io::{AsyncRead, AsyncWrite, ReadBuf};
use tokio_native_tls::{native_tls::Error, TlsAcceptor}; use tokio_native_tls::{native_tls::Error, TlsAcceptor};
use super::{TlsError, DEFAULT_TLS_HANDSHAKE_TIMEOUT, MAX_CONN_COUNTER}; use super::{TlsError, DEFAULT_TLS_HANDSHAKE_TIMEOUT, MAX_CONN_COUNTER};
use crate::impl_more;
pub mod reexports { pub mod reexports {
//! Re-exports from `native-tls` that are useful for acceptors. //! Re-exports from `native-tls` that are useful for acceptors.
@@ -35,9 +34,8 @@ pub mod reexports {
/// Wraps a `native-tls` based async TLS stream in order to implement [`ActixStream`]. /// Wraps a `native-tls` based async TLS stream in order to implement [`ActixStream`].
pub struct TlsStream<IO>(tokio_native_tls::TlsStream<IO>); pub struct TlsStream<IO>(tokio_native_tls::TlsStream<IO>);
impl_more::from! { tokio_native_tls::TlsStream<IO> => TlsStream<IO> } impl_more::impl_from!(<IO> in tokio_native_tls::TlsStream<IO> => TlsStream<IO>);
impl_more::deref! { TlsStream<IO> => 0: tokio_native_tls::TlsStream<IO> } impl_more::impl_deref_and_mut!(<IO> in TlsStream<IO> => tokio_native_tls::TlsStream<IO>);
impl_more::deref_mut! { TlsStream<IO> => 0 }
impl<IO: ActixStream> AsyncRead for TlsStream<IO> { impl<IO: ActixStream> AsyncRead for TlsStream<IO> {
fn poll_read( fn poll_read(

View File

@@ -11,7 +11,6 @@ use std::{
time::Duration, time::Duration,
}; };
use actix_codec::{AsyncRead, AsyncWrite, ReadBuf};
use actix_rt::{ use actix_rt::{
net::{ActixStream, Ready}, net::{ActixStream, Ready},
time::{sleep, Sleep}, time::{sleep, Sleep},
@@ -23,9 +22,9 @@ use actix_utils::{
}; };
use openssl::ssl::{Error, Ssl, SslAcceptor}; use openssl::ssl::{Error, Ssl, SslAcceptor};
use pin_project_lite::pin_project; use pin_project_lite::pin_project;
use tokio::io::{AsyncRead, AsyncWrite, ReadBuf};
use super::{TlsError, DEFAULT_TLS_HANDSHAKE_TIMEOUT, MAX_CONN_COUNTER}; use super::{TlsError, DEFAULT_TLS_HANDSHAKE_TIMEOUT, MAX_CONN_COUNTER};
use crate::impl_more;
pub mod reexports { pub mod reexports {
//! Re-exports from `openssl` that are useful for acceptors. //! Re-exports from `openssl` that are useful for acceptors.
@@ -38,9 +37,8 @@ pub mod reexports {
/// Wraps an `openssl` based async TLS stream in order to implement [`ActixStream`]. /// Wraps an `openssl` based async TLS stream in order to implement [`ActixStream`].
pub struct TlsStream<IO>(tokio_openssl::SslStream<IO>); pub struct TlsStream<IO>(tokio_openssl::SslStream<IO>);
impl_more::from! { tokio_openssl::SslStream<IO> => TlsStream<IO> } impl_more::impl_from!(<IO> in tokio_openssl::SslStream<IO> => TlsStream<IO>);
impl_more::deref! { TlsStream<IO> => 0: tokio_openssl::SslStream<IO> } impl_more::impl_deref_and_mut!(<IO> in TlsStream<IO> => tokio_openssl::SslStream<IO>);
impl_more::deref_mut! { TlsStream<IO> => 0 }
impl<IO: ActixStream> AsyncRead for TlsStream<IO> { impl<IO: ActixStream> AsyncRead for TlsStream<IO> {
fn poll_read( fn poll_read(

View File

@@ -12,7 +12,6 @@ use std::{
time::Duration, time::Duration,
}; };
use actix_codec::{AsyncRead, AsyncWrite, ReadBuf};
use actix_rt::{ use actix_rt::{
net::{ActixStream, Ready}, net::{ActixStream, Ready},
time::{sleep, Sleep}, time::{sleep, Sleep},
@@ -23,11 +22,11 @@ use actix_utils::{
future::{ready, Ready as FutReady}, future::{ready, Ready as FutReady},
}; };
use pin_project_lite::pin_project; use pin_project_lite::pin_project;
use tokio::io::{AsyncRead, AsyncWrite, ReadBuf};
use tokio_rustls::rustls::ServerConfig; use tokio_rustls::rustls::ServerConfig;
use tokio_rustls::{Accept, TlsAcceptor}; use tokio_rustls::{Accept, TlsAcceptor};
use super::{TlsError, DEFAULT_TLS_HANDSHAKE_TIMEOUT, MAX_CONN_COUNTER}; use super::{TlsError, DEFAULT_TLS_HANDSHAKE_TIMEOUT, MAX_CONN_COUNTER};
use crate::impl_more;
pub mod reexports { pub mod reexports {
//! Re-exports from `rustls` that are useful for acceptors. //! Re-exports from `rustls` that are useful for acceptors.
@@ -38,9 +37,8 @@ pub mod reexports {
/// Wraps a `rustls` based async TLS stream in order to implement [`ActixStream`]. /// Wraps a `rustls` based async TLS stream in order to implement [`ActixStream`].
pub struct TlsStream<IO>(tokio_rustls::server::TlsStream<IO>); pub struct TlsStream<IO>(tokio_rustls::server::TlsStream<IO>);
impl_more::from! { tokio_rustls::server::TlsStream<IO> => TlsStream<IO> } impl_more::impl_from!(<IO> in tokio_rustls::server::TlsStream<IO> => TlsStream<IO>);
impl_more::deref! { TlsStream<IO> => 0: tokio_rustls::server::TlsStream<IO> } impl_more::impl_deref_and_mut!(<IO> in TlsStream<IO> => tokio_rustls::server::TlsStream<IO>);
impl_more::deref_mut! { TlsStream<IO> => 0 }
impl<IO: ActixStream> AsyncRead for TlsStream<IO> { impl<IO: ActixStream> AsyncRead for TlsStream<IO> {
fn poll_read( fn poll_read(

View File

@@ -1,5 +1,4 @@
use super::Host; use super::Host;
use crate::impl_more;
/// Wraps underlying I/O and the connection request that initiated it. /// Wraps underlying I/O and the connection request that initiated it.
#[derive(Debug)] #[derive(Debug)]
@@ -8,8 +7,7 @@ pub struct Connection<R, IO> {
pub(crate) io: IO, pub(crate) io: IO,
} }
impl_more::deref! { Connection<R, IO> => io: IO } impl_more::impl_deref_and_mut!(<R, IO> in Connection<R, IO> => io: IO);
impl_more::deref_mut! { Connection<R, IO> => io }
impl<R, IO> Connection<R, IO> { impl<R, IO> Connection<R, IO> {
/// Construct new `Connection` from request and IO parts. /// Construct new `Connection` from request and IO parts.

View File

@@ -27,25 +27,25 @@ pub trait Host: Unpin + 'static {
impl Host for String { impl Host for String {
fn hostname(&self) -> &str { fn hostname(&self) -> &str {
str_split_once(self, ':') self.split_once(':')
.map(|(hostname, _)| hostname) .map(|(hostname, _)| hostname)
.unwrap_or(self) .unwrap_or(self)
} }
fn port(&self) -> Option<u16> { fn port(&self) -> Option<u16> {
str_split_once(self, ':').and_then(|(_, port)| port.parse().ok()) self.split_once(':').and_then(|(_, port)| port.parse().ok())
} }
} }
impl Host for &'static str { impl Host for &'static str {
fn hostname(&self) -> &str { fn hostname(&self) -> &str {
str_split_once(self, ':') self.split_once(':')
.map(|(hostname, _)| hostname) .map(|(hostname, _)| hostname)
.unwrap_or(self) .unwrap_or(self)
} }
fn port(&self) -> Option<u16> { fn port(&self) -> Option<u16> {
str_split_once(self, ':').and_then(|(_, port)| port.parse().ok()) self.split_once(':').and_then(|(_, port)| port.parse().ok())
} }
} }
@@ -69,11 +69,3 @@ mod tests {
assert_connection_info_eq!("example.com:false:false", "example.com", None); assert_connection_info_eq!("example.com:false:false", "example.com", None);
} }
} }
// `str::split_once` is stabilized in 1.52.0
fn str_split_once(str: &str, delimiter: char) -> Option<(&str, &str)> {
let mut splitn = str.splitn(2, delimiter);
let prefix = splitn.next()?;
let suffix = splitn.next()?;
Some((prefix, suffix))
}

View File

@@ -20,7 +20,6 @@ pub mod reexports {
//! Re-exports from `native-tls` and `tokio-native-tls` that are useful for connectors. //! Re-exports from `native-tls` and `tokio-native-tls` that are useful for connectors.
pub use tokio_native_tls::native_tls::TlsConnector; pub use tokio_native_tls::native_tls::TlsConnector;
pub use tokio_native_tls::TlsStream as AsyncTlsStream; pub use tokio_native_tls::TlsStream as AsyncTlsStream;
} }
@@ -75,16 +74,16 @@ where
let connector = self.connector.clone(); let connector = self.connector.clone();
Box::pin(async move { Box::pin(async move {
trace!("SSL Handshake start for: {:?}", stream.hostname()); trace!("TLS handshake start for: {:?}", stream.hostname());
connector connector
.connect(stream.hostname(), io) .connect(stream.hostname(), io)
.await .await
.map(|res| { .map(|res| {
trace!("SSL Handshake success: {:?}", stream.hostname()); trace!("TLS handshake success: {:?}", stream.hostname());
stream.replace_io(res).1 stream.replace_io(res).1
}) })
.map_err(|e| { .map_err(|e| {
trace!("SSL Handshake error: {:?}", e); trace!("TLS handshake error: {:?}", e);
io::Error::new(io::ErrorKind::Other, format!("{}", e)) io::Error::new(io::ErrorKind::Other, format!("{}", e))
}) })
}) })

View File

@@ -25,7 +25,6 @@ pub mod reexports {
pub use openssl::ssl::{ pub use openssl::ssl::{
Error, HandshakeError, SslConnector, SslConnectorBuilder, SslMethod, Error, HandshakeError, SslConnector, SslConnectorBuilder, SslMethod,
}; };
pub use tokio_openssl::SslStream as AsyncSslStream; pub use tokio_openssl::SslStream as AsyncSslStream;
} }
@@ -98,7 +97,8 @@ where
actix_service::always_ready!(); actix_service::always_ready!();
fn call(&self, stream: Connection<R, IO>) -> Self::Future { fn call(&self, stream: Connection<R, IO>) -> Self::Future {
trace!("SSL Handshake start for: {:?}", stream.hostname()); trace!("TLS handshake start for: {:?}", stream.hostname());
let (io, stream) = stream.replace_io(()); let (io, stream) = stream.replace_io(());
let host = stream.hostname(); let host = stream.hostname();
@@ -138,11 +138,11 @@ where
match ready!(Pin::new(this.io.as_mut().unwrap()).poll_connect(cx)) { match ready!(Pin::new(this.io.as_mut().unwrap()).poll_connect(cx)) {
Ok(_) => { Ok(_) => {
let stream = this.stream.take().unwrap(); let stream = this.stream.take().unwrap();
trace!("SSL Handshake success: {:?}", stream.hostname()); trace!("TLS handshake success: {:?}", stream.hostname());
Poll::Ready(Ok(stream.replace_io(this.io.take().unwrap()).1)) Poll::Ready(Ok(stream.replace_io(this.io.take().unwrap()).1))
} }
Err(err) => { Err(err) => {
trace!("SSL Handshake error: {:?}", err); trace!("TLS handshake error: {:?}", err);
Poll::Ready(Err(io::Error::new( Poll::Ready(Err(io::Error::new(
io::ErrorKind::Other, io::ErrorKind::Other,
format!("{}", err), format!("{}", err),

View File

@@ -26,10 +26,8 @@ use crate::connect::{Connection, Host};
pub mod reexports { pub mod reexports {
//! Re-exports from `rustls` and `webpki_roots` that are useful for connectors. //! Re-exports from `rustls` and `webpki_roots` that are useful for connectors.
pub use tokio_rustls::rustls::ClientConfig;
pub use tokio_rustls::client::TlsStream as AsyncTlsStream; pub use tokio_rustls::client::TlsStream as AsyncTlsStream;
pub use tokio_rustls::rustls::ClientConfig;
pub use webpki_roots::TLS_SERVER_ROOTS; pub use webpki_roots::TLS_SERVER_ROOTS;
} }
@@ -103,7 +101,7 @@ where
actix_service::always_ready!(); actix_service::always_ready!();
fn call(&self, connection: Connection<R, IO>) -> Self::Future { fn call(&self, connection: Connection<R, IO>) -> Self::Future {
trace!("SSL Handshake start for: {:?}", connection.hostname()); trace!("TLS handshake start for: {:?}", connection.hostname());
let (stream, connection) = connection.replace_io(()); let (stream, connection) = connection.replace_io(());
match ServerName::try_from(connection.hostname()) { match ServerName::try_from(connection.hostname()) {
@@ -142,7 +140,7 @@ where
Self::Future { connect, connection } => { Self::Future { connect, connection } => {
let stream = ready!(Pin::new(connect).poll(cx))?; let stream = ready!(Pin::new(connect).poll(cx))?;
let connection = connection.take().unwrap(); let connection = connection.take().unwrap();
trace!("SSL Handshake success: {:?}", connection.hostname()); trace!("TLS handshake success: {:?}", connection.hostname());
Poll::Ready(Ok(connection.replace_io(stream).1)) Poll::Ready(Ok(connection.replace_io(stream).1))
} }
} }

View File

@@ -114,8 +114,8 @@ impl<R: Host> TcpConnectorFut<R> {
stream: ReusableBoxFuture::new(connect(addr, local_addr)), stream: ReusableBoxFuture::new(connect(addr, local_addr)),
}, },
// when resolver returns multiple socket addr for request they would be popped from // When resolver returns multiple socket addr for request they would be popped from
// front end of queue and returns with the first successful tcp connection. // front end of queue and returns with the first successful TCP connection.
ConnectAddrs::Multi(mut addrs) => { ConnectAddrs::Multi(mut addrs) => {
let addr = addrs.pop_front().unwrap(); let addr = addrs.pop_front().unwrap();

View File

@@ -1,40 +0,0 @@
/// A helper to implement `Deref` for a type.
#[macro_export]
macro_rules! deref {
($ty:ident $(<$($generic:ident),*>)? => $field:tt: $target:ty) => {
impl $(<$($generic),*>)? ::core::ops::Deref for $ty $(<$($generic),*>)? {
type Target = $target;
fn deref(&self) -> &Self::Target {
&self.$field
}
}
};
}
/// A helper to implement `DerefMut` for a type.
#[macro_export]
macro_rules! deref_mut {
($ty:ident $(<$($generic:ident),*>)? => $field:tt) => {
impl $(<$($generic),*>)? ::core::ops::DerefMut for $ty $(<$($generic),*>)? {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.$field
}
}
};
}
/// A helper to implement `From` for a unit struct.
#[macro_export]
macro_rules! from {
($from:ty => $ty:ident $(<$($generic:ident),*>)?) => {
impl $(<$($generic),*>)? ::core::convert::From<$from> for $ty $(<$($generic),*>)? {
fn from(from: $from) -> Self {
Self(from)
}
}
};
}
#[allow(unused_imports)]
pub(crate) use crate::{deref, deref_mut, from};

View File

@@ -18,5 +18,3 @@ pub mod accept;
#[cfg(feature = "connect")] #[cfg(feature = "connect")]
#[cfg_attr(docsrs, doc(cfg(feature = "connect")))] #[cfg_attr(docsrs, doc(cfg(feature = "connect")))]
pub mod connect; pub mod connect;
mod impl_more;

View File

@@ -51,13 +51,13 @@ fn openssl_acceptor(cert: String, key: String) -> tls_openssl::ssl::SslAcceptor
mod danger { mod danger {
use std::time::SystemTime; use std::time::SystemTime;
use super::*;
use tokio_rustls::rustls::{ use tokio_rustls::rustls::{
self, self,
client::{ServerCertVerified, ServerCertVerifier}, client::{ServerCertVerified, ServerCertVerifier},
}; };
use super::*;
pub struct NoCertificateVerification; pub struct NoCertificateVerification;
impl ServerCertVerifier for NoCertificateVerification { impl ServerCertVerifier for NoCertificateVerification {

View File

@@ -9,11 +9,10 @@ use actix_codec::{BytesCodec, Framed};
use actix_rt::net::TcpStream; use actix_rt::net::TcpStream;
use actix_server::TestServer; use actix_server::TestServer;
use actix_service::{fn_service, Service, ServiceFactory}; use actix_service::{fn_service, Service, ServiceFactory};
use actix_tls::connect::{ConnectError, ConnectInfo, Connection, Connector, Host};
use bytes::Bytes; use bytes::Bytes;
use futures_util::sink::SinkExt; use futures_util::sink::SinkExt;
use actix_tls::connect::{ConnectError, ConnectInfo, Connection, Connector, Host};
#[cfg(feature = "openssl")] #[cfg(feature = "openssl")]
#[actix_rt::test] #[actix_rt::test]
async fn test_string() { async fn test_string() {
@@ -144,6 +143,9 @@ async fn test_local_addr() {
}) })
}); });
// if you've arrived here because of a failing test on macOS run this in your terminal:
// sudo ifconfig lo0 alias 127.0.0.3
let conn = Connector::default().service(); let conn = Connector::default().service();
let local = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 3)); let local = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 3));

View File

@@ -8,11 +8,10 @@ use std::{
use actix_rt::net::TcpStream; use actix_rt::net::TcpStream;
use actix_server::TestServer; use actix_server::TestServer;
use actix_service::{fn_service, Service, ServiceFactory}; use actix_service::{fn_service, Service, ServiceFactory};
use futures_core::future::LocalBoxFuture;
use actix_tls::connect::{ use actix_tls::connect::{
ConnectError, ConnectInfo, Connection, Connector, Host, Resolve, Resolver, ConnectError, ConnectInfo, Connection, Connector, Host, Resolve, Resolver,
}; };
use futures_core::future::LocalBoxFuture;
#[actix_rt::test] #[actix_rt::test]
async fn custom_resolver() { async fn custom_resolver() {

View File

@@ -1,7 +1,7 @@
# Changes # Changes
## Unreleased - 2022-xx-xx ## Unreleased - 2022-xx-xx
- Minimum supported Rust version (MSRV) is now 1.49. - Minimum supported Rust version (MSRV) is now 1.57.
## 0.1.0 - 2020-01-15 ## 0.1.0 - 2020-01-15

View File

@@ -16,12 +16,12 @@ name = "actix_tracing"
path = "src/lib.rs" path = "src/lib.rs"
[dependencies] [dependencies]
actix-service = "2.0.0" actix-service = "2"
actix-utils = "3.0.0" actix-utils = "3"
tracing = "0.1" tracing = "0.1.35"
tracing-futures = "0.2" tracing-futures = "0.2"
[dev_dependencies] [dev_dependencies]
actix-rt = "2.0.0" actix-rt = "2"
slab = "0.4" slab = "0.4"

View File

@@ -118,8 +118,6 @@ where
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*;
use std::cell::RefCell; use std::cell::RefCell;
use std::collections::{BTreeMap, BTreeSet}; use std::collections::{BTreeMap, BTreeSet};
use std::sync::{Arc, RwLock}; use std::sync::{Arc, RwLock};
@@ -128,6 +126,8 @@ mod test {
use slab::Slab; use slab::Slab;
use tracing::{span, Event, Level, Metadata, Subscriber}; use tracing::{span, Event, Level, Metadata, Subscriber};
use super::*;
thread_local! { thread_local! {
static SPAN: RefCell<Vec<span::Id>> = RefCell::new(Vec::new()); static SPAN: RefCell<Vec<span::Id>> = RefCell::new(Vec::new());
} }

View File

@@ -1,7 +1,10 @@
# Changes # Changes
## Unreleased - 2022-xx-xx ## Unreleased - 2022-xx-xx
- Minimum supported Rust version (MSRV) is now 1.49.
## 3.0.1 - 2022-10-21
- Minimum supported Rust version (MSRV) is now 1.57.
## 3.0.0 - 2021-04-16 ## 3.0.0 - 2021-04-16

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "actix-utils" name = "actix-utils"
version = "3.0.0" version = "3.0.1"
authors = [ authors = [
"Nikolay Kim <fafhrd91@gmail.com>", "Nikolay Kim <fafhrd91@gmail.com>",
"Rob Ede <robjtede@icloud.com>", "Rob Ede <robjtede@icloud.com>",

View File

@@ -1,4 +1,4 @@
//! Asynchronous values. //! Helpers for constructing futures.
mod either; mod either;
mod poll_fn; mod poll_fn;

View File

@@ -8,6 +8,31 @@ use core::{
}; };
/// Creates a future driven by the provided function that receives a task context. /// Creates a future driven by the provided function that receives a task context.
///
/// # Examples
/// ```
/// # use std::task::Poll;
/// # use actix_utils::future::poll_fn;
/// # async fn test_poll_fn() {
/// let res = poll_fn(|_| Poll::Ready(42)).await;
/// assert_eq!(res, 42);
///
/// let mut i = 5;
/// let res = poll_fn(|cx| {
/// i -= 1;
///
/// if i > 0 {
/// cx.waker().wake_by_ref();
/// Poll::Pending
/// } else {
/// Poll::Ready(42)
/// }
/// })
/// .await;
/// assert_eq!(res, 42);
/// # }
/// # actix_rt::Runtime::new().unwrap().block_on(test_poll_fn());
/// ```
#[inline] #[inline]
pub fn poll_fn<F, T>(f: F) -> PollFn<F> pub fn poll_fn<F, T>(f: F) -> PollFn<F>
where where
@@ -16,13 +41,11 @@ where
PollFn { f } PollFn { f }
} }
/// A Future driven by the inner function. /// Future for the [`poll_fn`] function.
pub struct PollFn<F> { pub struct PollFn<F> {
f: F, f: F,
} }
impl<F> Unpin for PollFn<F> {}
impl<F> fmt::Debug for PollFn<F> { impl<F> fmt::Debug for PollFn<F> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("PollFn").finish() f.debug_struct("PollFn").finish()
@@ -36,15 +59,22 @@ where
type Output = T; type Output = T;
#[inline] #[inline]
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
(self.f)(cx) // SAFETY: we are not moving out of the pinned field
// see https://github.com/rust-lang/rust/pull/102737
(unsafe { &mut self.get_unchecked_mut().f })(cx)
} }
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::marker::PhantomPinned;
use super::*; use super::*;
static_assertions::assert_impl_all!(PollFn<()>: Unpin);
static_assertions::assert_not_impl_all!(PollFn<PhantomPinned>: Unpin);
#[actix_rt::test] #[actix_rt::test]
async fn test_poll_fn() { async fn test_poll_fn() {
let res = poll_fn(|_| Poll::Ready(42)).await; let res = poll_fn(|_| Poll::Ready(42)).await;
@@ -64,4 +94,29 @@ mod tests {
.await; .await;
assert_eq!(res, 42); assert_eq!(res, 42);
} }
// following soundness tests taken from https://github.com/tokio-rs/tokio/pull/5087
#[allow(dead_code)]
fn require_send<T: Send>(_t: &T) {}
#[allow(dead_code)]
fn require_sync<T: Sync>(_t: &T) {}
trait AmbiguousIfUnpin<A> {
fn some_item(&self) {}
}
impl<T: ?Sized> AmbiguousIfUnpin<()> for T {}
impl<T: ?Sized + Unpin> AmbiguousIfUnpin<[u8; 0]> for T {}
const _: fn() = || {
let pinned = std::marker::PhantomPinned;
let f = poll_fn(move |_| {
// Use `pinned` to take ownership of it.
let _ = &pinned;
std::task::Poll::Pending::<()>
});
require_send(&f);
require_sync(&f);
AmbiguousIfUnpin::some_item(&f);
};
} }

View File

@@ -1,4 +1,4 @@
//! When MSRV is 1.48, replace with `core::future::Ready` and `core::future::ready()`. //! When `core::future::Ready` has a `into_inner()` method, this can be deprecated.
use core::{ use core::{
future::Future, future::Future,
@@ -6,7 +6,7 @@ use core::{
task::{Context, Poll}, task::{Context, Poll},
}; };
/// Future for the [`ready`](ready()) function. /// Future for the [`ready`] function.
/// ///
/// Panic will occur if polled more than once. /// Panic will occur if polled more than once.
/// ///

View File

@@ -1,8 +1,28 @@
# Changes # Changes
## Unreleased - 2022-xx-xx ## Unreleased - 2022-xx-xx
## 1.2.1 - 2022-11-12
- Fix `#[no_std]` compatibility. [#471]
[#471]: https://github.com/actix/actix-net/pull/471
## 1.2.0 - 2022-11-07
- Add `ByteString::slice_ref` which can safely slice a `ByteString` into a new one with zero copy. [#470]
- Minimum supported Rust version (MSRV) is now 1.57.
[#470]: https://github.com/actix/actix-net/pull/470
## 1.1.0 - 2022-06-11
- Implement `From<Box<str>>` for `ByteString`. [#458]
- Implement `Into<String>` for `ByteString`. [#458]
- Minimum supported Rust version (MSRV) is now 1.49. - Minimum supported Rust version (MSRV) is now 1.49.
[#458]: https://github.com/actix/actix-net/pull/458
## 1.0.0 - 2020-12-31 ## 1.0.0 - 2020-12-31
- Update `bytes` dependency to `1`. - Update `bytes` dependency to `1`.

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "bytestring" name = "bytestring"
version = "1.0.0" version = "1.2.1"
authors = [ authors = [
"Nikolay Kim <fafhrd91@gmail.com>", "Nikolay Kim <fafhrd91@gmail.com>",
"Rob Ede <robjtede@icloud.com>", "Rob Ede <robjtede@icloud.com>",
@@ -18,11 +18,11 @@ name = "bytestring"
path = "src/lib.rs" path = "src/lib.rs"
[dependencies] [dependencies]
bytes = "1" bytes = { version = "1.2", default-features = false }
serde = { version = "1.0", optional = true } serde = { version = "1.0", optional = true }
[dev-dependencies] [dev-dependencies]
ahash = { version = "0.7.6", default-features = false } ahash = { version = "0.8", default-features = false }
serde_json = "1.0" serde_json = "1.0"
static_assertions = "1.1" static_assertions = "1.1"
rustversion = "1" rustversion = "1"

View File

@@ -6,7 +6,11 @@
extern crate alloc; extern crate alloc;
use alloc::{string::String, vec::Vec}; use alloc::{
boxed::Box,
string::{String, ToString},
vec::Vec,
};
use core::{borrow, convert::TryFrom, fmt, hash, ops, str}; use core::{borrow, convert::TryFrom, fmt, hash, ops, str};
use bytes::Bytes; use bytes::Bytes;
@@ -46,6 +50,33 @@ impl ByteString {
pub const unsafe fn from_bytes_unchecked(src: Bytes) -> ByteString { pub const unsafe fn from_bytes_unchecked(src: Bytes) -> ByteString {
Self(src) Self(src)
} }
/// Returns a byte string that is equivalent to the given `subset`.
///
/// When processing a `ByteString` buffer with other tools, one often gets a `&str` which is in
/// fact a slice of the `ByteString`; i.e., a subset of it. This function turns that `&str` into
/// another `ByteString`, as if one had sliced the `ByteString` with the offsets that correspond
/// to `subset`.
///
/// Corresponds to [`Bytes::slice_ref`].
///
/// This operation is `O(1)`.
///
/// # Panics
/// Requires that the given `subset` str is in fact contained within the `ByteString` buffer;
/// otherwise this function will panic.
///
/// # Examples
/// ```
/// # use bytestring::ByteString;
/// let string = ByteString::from_static(" foo ");
/// let subset = string.trim();
/// let substring = string.slice_ref(subset);
/// assert_eq!(substring, "foo");
/// ```
pub fn slice_ref(&self, subset: &str) -> Self {
Self(self.0.slice_ref(subset.as_bytes()))
}
} }
impl PartialEq<str> for ByteString { impl PartialEq<str> for ByteString {
@@ -68,7 +99,7 @@ impl AsRef<[u8]> for ByteString {
impl AsRef<str> for ByteString { impl AsRef<str> for ByteString {
fn as_ref(&self) -> &str { fn as_ref(&self) -> &str {
&*self self
} }
} }
@@ -92,7 +123,7 @@ impl ops::Deref for ByteString {
impl borrow::Borrow<str> for ByteString { impl borrow::Borrow<str> for ByteString {
fn borrow(&self) -> &str { fn borrow(&self) -> &str {
&*self self
} }
} }
@@ -110,6 +141,20 @@ impl From<&str> for ByteString {
} }
} }
impl From<Box<str>> for ByteString {
#[inline]
fn from(value: Box<str>) -> Self {
Self(Bytes::from(value.into_boxed_bytes()))
}
}
impl From<ByteString> for String {
#[inline]
fn from(value: ByteString) -> Self {
value.to_string()
}
}
impl TryFrom<&[u8]> for ByteString { impl TryFrom<&[u8]> for ByteString {
type Error = str::Utf8Error; type Error = str::Utf8Error;
@@ -219,11 +264,11 @@ mod serde {
#[cfg(test)] #[cfg(test)]
mod serde_impl_tests { mod serde_impl_tests {
use super::*;
use serde::de::DeserializeOwned; use serde::de::DeserializeOwned;
use static_assertions::assert_impl_all; use static_assertions::assert_impl_all;
use super::*;
assert_impl_all!(ByteString: Serialize, DeserializeOwned); assert_impl_all!(ByteString: Serialize, DeserializeOwned);
} }
} }
@@ -331,4 +376,10 @@ mod test {
let s = serde_json::to_string(&ByteString::from_static("nice bytes")).unwrap(); let s = serde_json::to_string(&ByteString::from_static("nice bytes")).unwrap();
assert_eq!(s, r#""nice bytes""#); assert_eq!(s, r#""nice bytes""#);
} }
#[test]
#[should_panic]
fn test_slice_ref_catches_not_a_subset() {
ByteString::from_static("foo bar").slice_ref("foo");
}
} }

View File

@@ -1 +1 @@
msrv = "1.48" msrv = "1.57"

View File

@@ -1,6 +1,10 @@
# Changes # Changes
## Unreleased - 2022-xx-xx ## Unreleased - 2022-xx-xx
- Minimum supported Rust version (MSRV) is now 1.57.
## 0.1.3 - 2022-05-03
- Minimum supported Rust version (MSRV) is now 1.49. - Minimum supported Rust version (MSRV) is now 1.49.

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "local-channel" name = "local-channel"
version = "0.1.2" version = "0.1.3"
description = "A non-threadsafe multi-producer, single-consumer, futures-aware, FIFO queue" description = "A non-threadsafe multi-producer, single-consumer, futures-aware, FIFO queue"
authors = [ authors = [
"Nikolay Kim <fafhrd91@gmail.com>", "Nikolay Kim <fafhrd91@gmail.com>",

View File

@@ -0,0 +1 @@
../LICENSE-APACHE

1
local-channel/LICENSE-MIT Symbolic link
View File

@@ -0,0 +1 @@
../LICENSE-MIT

View File

@@ -1,6 +1,10 @@
# Changes # Changes
## Unreleased - 2022-xx-xx ## Unreleased - 2022-xx-xx
- Minimum supported Rust version (MSRV) is now 1.57.
## 0.1.3 - 2022-05-03
- Minimum supported Rust version (MSRV) is now 1.49. - Minimum supported Rust version (MSRV) is now 1.49.

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "local-waker" name = "local-waker"
version = "0.1.2" version = "0.1.3"
description = "A synchronization primitive for thread-local task wakeup" description = "A synchronization primitive for thread-local task wakeup"
authors = [ authors = [
"Nikolay Kim <fafhrd91@gmail.com>", "Nikolay Kim <fafhrd91@gmail.com>",

1
local-waker/LICENSE-APACHE Symbolic link
View File

@@ -0,0 +1 @@
../LICENSE-APACHE

1
local-waker/LICENSE-MIT Symbolic link
View File

@@ -0,0 +1 @@
../LICENSE-MIT

View File

@@ -1,2 +1,2 @@
max_width = 96 max_width = 96
reorder_imports = true group_imports = "StdExternalCrate"