diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index b0ee627d..d55ce1c1 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -29,18 +29,16 @@ jobs: uses: actions-rs/cargo@v1 with: command: generate-lockfile - - name: Cache cargo registry - uses: actions/cache@v1 + - name: Cache cargo dirs + uses: actions/cache@v2 with: - path: ~/.cargo/registry - key: ${{ matrix.version }}-x86_64-unknown-linux-gnu-cargo-registry-trimmed-${{ hashFiles('**/Cargo.lock') }} - - name: Cache cargo index - uses: actions/cache@v1 - with: - path: ~/.cargo/git - key: ${{ matrix.version }}-x86_64-unknown-linux-gnu-cargo-index-trimmed-${{ hashFiles('**/Cargo.lock') }} + path: + ~/.cargo/registry + ~/.cargo/git + ~/.cargo/bin + key: ${{ matrix.version }}-x86_64-unknown-linux-gnu-cargo-trimmed-${{ hashFiles('**/Cargo.lock') }} - name: Cache cargo build - uses: actions/cache@v1 + uses: actions/cache@v2 with: path: target key: ${{ matrix.version }}-x86_64-unknown-linux-gnu-cargo-build-trimmed-${{ hashFiles('**/Cargo.lock') }} @@ -59,19 +57,18 @@ jobs: args: --all --all-features --no-fail-fast -- --nocapture - name: Generate coverage file - if: matrix.version == 'stable' && github.ref == 'refs/heads/master' + if: matrix.version == 'stable' && (github.ref == 'refs/heads/master' || github.event_name == 'pull_request') run: | - cargo install cargo-tarpaulin + which cargo-tarpaulin || cargo install cargo-tarpaulin cargo tarpaulin --out Xml --workspace --all-features - name: Upload to Codecov - if: matrix.version == 'stable' && github.ref == 'refs/heads/master' + if: matrix.version == 'stable' && (github.ref == 'refs/heads/master' || github.event_name == 'pull_request') uses: codecov/codecov-action@v1 with: - token: ${{ secrets.CODECOV_TOKEN }} file: cobertura.xml - name: Clear the cargo caches run: | - cargo install cargo-cache --no-default-features --features ci-autoclean + which cargo-cache || cargo install cargo-cache --no-default-features --features ci-autoclean cargo-cache diff --git a/.github/workflows/windows-mingw.yml b/.github/workflows/windows-mingw.yml index c036d9b5..9f6ea51d 100644 --- a/.github/workflows/windows-mingw.yml +++ b/.github/workflows/windows-mingw.yml @@ -2,9 +2,6 @@ name: CI (Windows-mingw) on: [push, pull_request] -env: - OPENSSL_DIR: d:\a\_temp\msys\msys64\usr - jobs: build_and_test: strategy: @@ -30,25 +27,13 @@ jobs: - name: Install MSYS2 uses: numworks/setup-msys2@v1 - - name: Install OpenSSL + - name: Install packages run: | - msys2do pacman --noconfirm -S openssl-devel pkg-config - - - name: Copy and check libs - run: | - Copy-Item d:\a\_temp\msys\msys64\usr\lib\libssl.dll.a d:\a\_temp\msys\msys64\usr\lib\libssl.dll - Copy-Item d:\a\_temp\msys\msys64\usr\lib\libcrypto.dll.a d:\a\_temp\msys\msys64\usr\lib\libcrypto.dll - Get-ChildItem d:\a\_temp\msys\msys64\usr\lib - Get-ChildItem d:\a\_temp\msys\msys64\usr + msys2do pacman -Sy --noconfirm pacman + msys2do pacman --noconfirm -S base-devel pkg-config - name: check build uses: actions-rs/cargo@v1 with: command: check args: --all --bins --examples --tests - - - name: tests - uses: actions-rs/cargo@v1 - with: - command: test - args: --all --all-features --no-fail-fast -- --nocapture diff --git a/actix-codec/Cargo.toml b/actix-codec/Cargo.toml index d647ab70..3c7a93bc 100644 --- a/actix-codec/Cargo.toml +++ b/actix-codec/Cargo.toml @@ -19,9 +19,9 @@ path = "src/lib.rs" [dependencies] bitflags = "1.2.1" bytes = "0.5.2" -futures-core = "0.3.1" -futures-sink = "0.3.1" +futures-core = { version = "0.3.4", default-features = false } +futures-sink = { version = "0.3.4", default-features = false } tokio = { version = "0.2.4", default-features=false } tokio-util = { version = "0.2.0", default-features=false, features=["codec"] } log = "0.4" -pin-project = "0.4.8" +pin-project = "0.4.17" diff --git a/actix-codec/src/lib.rs b/actix-codec/src/lib.rs index fc53b688..7c38bdf7 100644 --- a/actix-codec/src/lib.rs +++ b/actix-codec/src/lib.rs @@ -2,10 +2,12 @@ //! //! Contains adapters to go from streams of bytes, [`AsyncRead`] and //! [`AsyncWrite`], to framed streams implementing [`Sink`] and [`Stream`]. -//! Framed streams are also known as [transports]. +//! Framed streams are also known as `transports`. //! -//! [`AsyncRead`]: # -//! [`AsyncWrite`]: # +//! [`AsyncRead`]: AsyncRead +//! [`AsyncWrite`]: AsyncWrite +//! [`Sink`]: futures_sink::Sink +//! [`Stream`]: futures_core::Stream #![deny(rust_2018_idioms, warnings)] mod bcodec; diff --git a/actix-connect/CHANGES.md b/actix-connect/CHANGES.md index 90d6667b..7a230fe9 100644 --- a/actix-connect/CHANGES.md +++ b/actix-connect/CHANGES.md @@ -1,5 +1,22 @@ # Changes +## [2.0.0-alpha.3] - 2020-05-08 + +### Fixed + +* Corrected spelling of `ConnectError::Unresolverd` to `ConnectError::Unresolved` + +## [2.0.0-alpha.2] - 2020-03-08 + +### Changed + +* Update `trust-dns-proto` dependency to 0.19. [#116] +* Update `trust-dns-resolver` dependency to 0.19. [#116] +* `Address` trait is now required to have static lifetime. [#116] +* `start_resolver` and `start_default_resolver` are now `async` and may return a `ConnectError`. [#116] + +[#116]: https://github.com/actix/actix-net/pull/116 + ## [2.0.0-alpha.1] - 2020-03-03 ### Changed diff --git a/actix-connect/Cargo.toml b/actix-connect/Cargo.toml index 6beee4e7..bd72b22e 100644 --- a/actix-connect/Cargo.toml +++ b/actix-connect/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "actix-connect" -version = "2.0.0-alpha.1" +version = "2.0.0-alpha.3" authors = ["Nikolay Kim "] description = "Actix connect - tcp connector service" keywords = ["network", "framework", "async", "futures"] @@ -37,11 +37,11 @@ actix-utils = "1.0.6" actix-rt = "1.0.0" derive_more = "0.99.2" either = "1.5.3" -futures = "0.3.1" +futures-util = { version = "0.3.4", default-features = false } http = { version = "0.2.0", optional = true } log = "0.4" -trust-dns-proto = "=0.18.0-alpha.2" -trust-dns-resolver = "=0.18.0-alpha.2" +trust-dns-proto = { version = "0.19", default-features = false, features = ["tokio-runtime"] } +trust-dns-resolver = { version = "0.19", default-features = false, features = ["tokio-runtime", "system-config"] } # openssl open-ssl = { version="0.10", package = "openssl", optional = true } diff --git a/actix-connect/src/connect.rs b/actix-connect/src/connect.rs index 1a4c51c5..f4f7f6b7 100644 --- a/actix-connect/src/connect.rs +++ b/actix-connect/src/connect.rs @@ -6,7 +6,7 @@ use std::net::SocketAddr; use either::Either; /// Connect request -pub trait Address: Unpin { +pub trait Address: Unpin + 'static { /// Host name of the request fn host(&self) -> &str; diff --git a/actix-connect/src/connector.rs b/actix-connect/src/connector.rs index e2ed8e2b..e9fb1525 100644 --- a/actix-connect/src/connector.rs +++ b/actix-connect/src/connector.rs @@ -8,7 +8,7 @@ use std::task::{Context, Poll}; use actix_rt::net::TcpStream; use actix_service::{Service, ServiceFactory}; -use futures::future::{err, ok, BoxFuture, Either, FutureExt, Ready}; +use futures_util::future::{err, ok, BoxFuture, Either, FutureExt, Ready}; use super::connect::{Address, Connect, Connection}; use super::error::ConnectError; @@ -88,7 +88,7 @@ impl Service for TcpConnector { Either::Left(TcpConnectorResponse::new(req, port, addr)) } else { error!("TCP connector: got unresolved address"); - Either::Right(err(ConnectError::Unresolverd)) + Either::Right(err(ConnectError::Unresolved)) } } } diff --git a/actix-connect/src/error.rs b/actix-connect/src/error.rs index 30946459..3c56f072 100644 --- a/actix-connect/src/error.rs +++ b/actix-connect/src/error.rs @@ -18,7 +18,7 @@ pub enum ConnectError { /// Unresolved host name #[display(fmt = "Connector received `Connect` method with unresolved host")] - Unresolverd, + Unresolved, /// Connection io error #[display(fmt = "{}", _0)] diff --git a/actix-connect/src/lib.rs b/actix-connect/src/lib.rs index 5de0b153..85dcf99e 100644 --- a/actix-connect/src/lib.rs +++ b/actix-connect/src/lib.rs @@ -25,7 +25,7 @@ use actix_rt::{net::TcpStream, Arbiter}; use actix_service::{pipeline, pipeline_factory, Service, ServiceFactory}; use trust_dns_resolver::config::{ResolverConfig, ResolverOpts}; use trust_dns_resolver::system_conf::read_system_conf; -use trust_dns_resolver::AsyncResolver; +use trust_dns_resolver::TokioAsyncResolver as AsyncResolver; pub mod resolver { pub use trust_dns_resolver::config::{ResolverConfig, ResolverOpts}; @@ -39,17 +39,18 @@ pub use self::error::ConnectError; pub use self::resolve::{Resolver, ResolverFactory}; pub use self::service::{ConnectService, ConnectServiceFactory, TcpConnectService}; -pub fn start_resolver(cfg: ResolverConfig, opts: ResolverOpts) -> AsyncResolver { - let (resolver, bg) = AsyncResolver::new(cfg, opts); - actix_rt::spawn(bg); - resolver +pub async fn start_resolver( + cfg: ResolverConfig, + opts: ResolverOpts, +) -> Result { + Ok(AsyncResolver::tokio(cfg, opts).await?) } struct DefaultResolver(AsyncResolver); -pub(crate) fn get_default_resolver() -> AsyncResolver { +pub(crate) async fn get_default_resolver() -> Result { if Arbiter::contains_item::() { - Arbiter::get_item(|item: &DefaultResolver| item.0.clone()) + Ok(Arbiter::get_item(|item: &DefaultResolver| item.0.clone())) } else { let (cfg, opts) = match read_system_conf() { Ok((cfg, opts)) => (cfg, opts), @@ -59,16 +60,15 @@ pub(crate) fn get_default_resolver() -> AsyncResolver { } }; - let (resolver, bg) = AsyncResolver::new(cfg, opts); - actix_rt::spawn(bg); + let resolver = AsyncResolver::tokio(cfg, opts).await?; Arbiter::set_item(DefaultResolver(resolver.clone())); - resolver + Ok(resolver) } } -pub fn start_default_resolver() -> AsyncResolver { - get_default_resolver() +pub async fn start_default_resolver() -> Result { + get_default_resolver().await } /// Create tcp connector service diff --git a/actix-connect/src/resolve.rs b/actix-connect/src/resolve.rs index 31ee05d0..faf68a19 100644 --- a/actix-connect/src/resolve.rs +++ b/actix-connect/src/resolve.rs @@ -5,9 +5,9 @@ use std::pin::Pin; use std::task::{Context, Poll}; use actix_service::{Service, ServiceFactory}; -use futures::future::{ok, Either, Ready}; -use trust_dns_resolver::lookup_ip::LookupIpFuture; -use trust_dns_resolver::{AsyncResolver, Background}; +use futures_util::future::{ok, Either, Ready}; +use trust_dns_resolver::TokioAsyncResolver as AsyncResolver; +use trust_dns_resolver::{error::ResolveError, lookup_ip::LookupIp}; use crate::connect::{Address, Connect}; use crate::error::ConnectError; @@ -106,7 +106,10 @@ impl Service for Resolver { type Request = Connect; type Response = Connect; type Error = ConnectError; - type Future = Either, Ready, Self::Error>>>; + type Future = Either< + Pin>>>, + Ready, Self::Error>>, + >; fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll> { Poll::Ready(Ok(())) @@ -119,32 +122,48 @@ impl Service for Resolver { req.addr = Some(either::Either::Left(SocketAddr::new(ip, req.port()))); Either::Right(ok(req)) } else { - trace!("DNS resolver: resolving host {:?}", req.host()); - if self.resolver.is_none() { - self.resolver = Some(get_default_resolver()); - } - Either::Left(ResolverFuture::new(req, self.resolver.as_ref().unwrap())) + let resolver = self.resolver.as_ref().map(AsyncResolver::clone); + Either::Left(Box::pin(async move { + trace!("DNS resolver: resolving host {:?}", req.host()); + let resolver = if let Some(resolver) = resolver { + resolver + } else { + get_default_resolver() + .await + .expect("Failed to get default resolver") + }; + ResolverFuture::new(req, &resolver).await + })) } } } +type LookupIpFuture = Pin>>>; + #[doc(hidden)] /// Resolver future pub struct ResolverFuture { req: Option>, - lookup: Background, + lookup: LookupIpFuture, } impl ResolverFuture { pub fn new(req: Connect, resolver: &AsyncResolver) -> Self { - let lookup = if let Some(host) = req.host().splitn(2, ':').next() { - resolver.lookup_ip(host) + let host = if let Some(host) = req.host().splitn(2, ':').next() { + host } else { - resolver.lookup_ip(req.host()) + req.host() }; + // Clone data to be moved to the lookup future + let host_clone = host.to_owned(); + let resolver_clone = resolver.clone(); + ResolverFuture { - lookup, + lookup: Box::pin(async move { + let resolver = resolver_clone; + resolver.lookup_ip(host_clone).await + }), req: Some(req), } } diff --git a/actix-connect/src/service.rs b/actix-connect/src/service.rs index 6a290929..f337382b 100644 --- a/actix-connect/src/service.rs +++ b/actix-connect/src/service.rs @@ -5,8 +5,8 @@ use std::task::{Context, Poll}; use actix_rt::net::TcpStream; use actix_service::{Service, ServiceFactory}; use either::Either; -use futures::future::{ok, Ready}; -use trust_dns_resolver::AsyncResolver; +use futures_util::future::{ok, Ready}; +use trust_dns_resolver::TokioAsyncResolver as AsyncResolver; use crate::connect::{Address, Connect, Connection}; use crate::connector::{TcpConnector, TcpConnectorFactory}; diff --git a/actix-connect/src/ssl/openssl.rs b/actix-connect/src/ssl/openssl.rs index f2fa1943..6858adbe 100644 --- a/actix-connect/src/ssl/openssl.rs +++ b/actix-connect/src/ssl/openssl.rs @@ -10,8 +10,8 @@ pub use tokio_openssl::{HandshakeError, SslStream}; use actix_codec::{AsyncRead, AsyncWrite}; use actix_rt::net::TcpStream; use actix_service::{Service, ServiceFactory}; -use futures::future::{err, ok, Either, FutureExt, LocalBoxFuture, Ready}; -use trust_dns_resolver::AsyncResolver; +use futures_util::future::{err, ok, Either, FutureExt, LocalBoxFuture, Ready}; +use trust_dns_resolver::TokioAsyncResolver as AsyncResolver; use crate::{ Address, Connect, ConnectError, ConnectService, ConnectServiceFactory, Connection, @@ -243,7 +243,7 @@ impl Future for OpensslConnectServiceResponse { fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { if let Some(ref mut fut) = self.fut1 { - match futures::ready!(Pin::new(fut).poll(cx)) { + match futures_util::ready!(Pin::new(fut).poll(cx)) { Ok(res) => { let _ = self.fut1.take(); self.fut2 = Some(self.openssl.call(res)); @@ -253,7 +253,7 @@ impl Future for OpensslConnectServiceResponse { } if let Some(ref mut fut) = self.fut2 { - match futures::ready!(Pin::new(fut).poll(cx)) { + match futures_util::ready!(Pin::new(fut).poll(cx)) { Ok(connect) => Poll::Ready(Ok(connect.into_parts().0)), Err(e) => Poll::Ready(Err(ConnectError::Io(io::Error::new( io::ErrorKind::Other, diff --git a/actix-connect/src/ssl/rustls.rs b/actix-connect/src/ssl/rustls.rs index 1964b3aa..3e646082 100644 --- a/actix-connect/src/ssl/rustls.rs +++ b/actix-connect/src/ssl/rustls.rs @@ -10,7 +10,7 @@ pub use tokio_rustls::{client::TlsStream, rustls::ClientConfig}; use actix_codec::{AsyncRead, AsyncWrite}; use actix_service::{Service, ServiceFactory}; -use futures::future::{ok, Ready}; +use futures_util::future::{ok, Ready}; use tokio_rustls::{Connect, TlsConnector}; use webpki::DNSNameRef; @@ -126,7 +126,7 @@ where fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { let this = self.get_mut(); Poll::Ready( - futures::ready!(Pin::new(&mut this.fut).poll(cx)).map(|stream| { + futures_util::ready!(Pin::new(&mut this.fut).poll(cx)).map(|stream| { let s = this.stream.take().unwrap(); trace!("SSL Handshake success: {:?}", s.host()); s.replace(stream).1 diff --git a/actix-connect/tests/test_connect.rs b/actix-connect/tests/test_connect.rs index 4e9fb40a..549d559f 100644 --- a/actix-connect/tests/test_connect.rs +++ b/actix-connect/tests/test_connect.rs @@ -5,7 +5,7 @@ use actix_rt::net::TcpStream; use actix_service::{fn_service, Service, ServiceFactory}; use actix_testing::TestServer; use bytes::Bytes; -use futures::SinkExt; +use futures_util::sink::SinkExt; use actix_connect::resolver::{ResolverConfig, ResolverOpts}; use actix_connect::Connect; @@ -14,12 +14,10 @@ use actix_connect::Connect; #[actix_rt::test] async fn test_string() { let srv = TestServer::with(|| { - fn_service(|io: TcpStream| { - async { - let mut framed = Framed::new(io, BytesCodec); - framed.send(Bytes::from_static(b"test")).await?; - Ok::<_, io::Error>(()) - } + fn_service(|io: TcpStream| async { + let mut framed = Framed::new(io, BytesCodec); + framed.send(Bytes::from_static(b"test")).await?; + Ok::<_, io::Error>(()) }) }); @@ -33,12 +31,10 @@ async fn test_string() { #[actix_rt::test] async fn test_rustls_string() { let srv = TestServer::with(|| { - fn_service(|io: TcpStream| { - async { - let mut framed = Framed::new(io, BytesCodec); - framed.send(Bytes::from_static(b"test")).await?; - Ok::<_, io::Error>(()) - } + fn_service(|io: TcpStream| async { + let mut framed = Framed::new(io, BytesCodec); + framed.send(Bytes::from_static(b"test")).await?; + Ok::<_, io::Error>(()) }) }); @@ -51,16 +47,14 @@ async fn test_rustls_string() { #[actix_rt::test] async fn test_static_str() { let srv = TestServer::with(|| { - fn_service(|io: TcpStream| { - async { - let mut framed = Framed::new(io, BytesCodec); - framed.send(Bytes::from_static(b"test")).await?; - Ok::<_, io::Error>(()) - } + fn_service(|io: TcpStream| async { + let mut framed = Framed::new(io, BytesCodec); + framed.send(Bytes::from_static(b"test")).await?; + Ok::<_, io::Error>(()) }) }); - let resolver = actix_connect::start_default_resolver(); + let resolver = actix_connect::start_default_resolver().await.unwrap(); let mut conn = actix_connect::new_connector(resolver.clone()); let con = conn.call(Connect::with("10", srv.addr())).await.unwrap(); @@ -75,17 +69,17 @@ async fn test_static_str() { #[actix_rt::test] async fn test_new_service() { let srv = TestServer::with(|| { - fn_service(|io: TcpStream| { - async { - let mut framed = Framed::new(io, BytesCodec); - framed.send(Bytes::from_static(b"test")).await?; - Ok::<_, io::Error>(()) - } + fn_service(|io: TcpStream| async { + let mut framed = Framed::new(io, BytesCodec); + framed.send(Bytes::from_static(b"test")).await?; + Ok::<_, io::Error>(()) }) }); let resolver = - actix_connect::start_resolver(ResolverConfig::default(), ResolverOpts::default()); + actix_connect::start_resolver(ResolverConfig::default(), ResolverOpts::default()) + .await + .unwrap(); let factory = actix_connect::new_connector_factory(resolver); @@ -100,12 +94,10 @@ async fn test_uri() { use std::convert::TryFrom; let srv = TestServer::with(|| { - fn_service(|io: TcpStream| { - async { - let mut framed = Framed::new(io, BytesCodec); - framed.send(Bytes::from_static(b"test")).await?; - Ok::<_, io::Error>(()) - } + fn_service(|io: TcpStream| async { + let mut framed = Framed::new(io, BytesCodec); + framed.send(Bytes::from_static(b"test")).await?; + Ok::<_, io::Error>(()) }) }); @@ -121,12 +113,10 @@ async fn test_rustls_uri() { use std::convert::TryFrom; let srv = TestServer::with(|| { - fn_service(|io: TcpStream| { - async { - let mut framed = Framed::new(io, BytesCodec); - framed.send(Bytes::from_static(b"test")).await?; - Ok::<_, io::Error>(()) - } + fn_service(|io: TcpStream| async { + let mut framed = Framed::new(io, BytesCodec); + framed.send(Bytes::from_static(b"test")).await?; + Ok::<_, io::Error>(()) }) }); diff --git a/actix-ioframe/Cargo.toml b/actix-ioframe/Cargo.toml index 13a7eeed..efc81740 100644 --- a/actix-ioframe/Cargo.toml +++ b/actix-ioframe/Cargo.toml @@ -22,10 +22,12 @@ actix-utils = "1.0.4" actix-rt = "1.0.0" bytes = "0.5.3" either = "1.5.3" -futures = "0.3.1" -pin-project = "0.4.6" +futures-sink = { version = "0.3.4", default-features = false } +futures-core = { version = "0.3.4", default-features = false } +pin-project = "0.4.17" log = "0.4" [dev-dependencies] -actix-connect = "2.0.0-alpha.1" +actix-connect = "2.0.0-alpha.2" actix-testing = "1.0.0" +futures-util = { version = "0.3.4", default-features = false } diff --git a/actix-ioframe/src/connect.rs b/actix-ioframe/src/connect.rs index 85248fe4..4e2980d1 100644 --- a/actix-ioframe/src/connect.rs +++ b/actix-ioframe/src/connect.rs @@ -4,7 +4,7 @@ use std::task::{Context, Poll}; use actix_codec::{AsyncRead, AsyncWrite, Decoder, Encoder, Framed}; use actix_utils::mpsc::Receiver; -use futures::Stream; +use futures_core::stream::Stream; pub struct Connect where @@ -90,7 +90,7 @@ where } } -impl futures::Sink<::Item> +impl futures_sink::Sink<::Item> for ConnectResult where Io: AsyncRead + AsyncWrite, diff --git a/actix-ioframe/src/dispatcher.rs b/actix-ioframe/src/dispatcher.rs index 3be8963a..b7d5dd9f 100644 --- a/actix-ioframe/src/dispatcher.rs +++ b/actix-ioframe/src/dispatcher.rs @@ -5,7 +5,7 @@ use std::task::{Context, Poll}; use actix_codec::{AsyncRead, AsyncWrite, Decoder, Encoder, Framed}; use actix_service::Service; use actix_utils::mpsc; -use futures::Stream; +use futures_core::stream::Stream; use pin_project::pin_project; use log::debug; diff --git a/actix-ioframe/src/service.rs b/actix-ioframe/src/service.rs index d679b45b..f3b5ab85 100644 --- a/actix-ioframe/src/service.rs +++ b/actix-ioframe/src/service.rs @@ -7,8 +7,7 @@ use std::task::{Context, Poll}; use actix_codec::{AsyncRead, AsyncWrite, Decoder, Encoder, Framed}; use actix_service::{IntoService, IntoServiceFactory, Service, ServiceFactory}; use either::Either; -use futures::{ready, Stream}; -use pin_project::project; +use futures_core::{ready, stream::Stream}; use crate::connect::{Connect, ConnectResult}; use crate::dispatcher::Dispatcher; @@ -336,7 +335,7 @@ where } } -#[pin_project::pin_project] +#[pin_project::pin_project(project = FramedServiceImplResponseInnerProj)] enum FramedServiceImplResponseInner where C: Service, Response = ConnectResult>, @@ -378,7 +377,6 @@ where ::Error: std::fmt::Debug, Out: Stream::Item> + Unpin, { - #[project] fn poll( self: Pin<&mut Self>, cx: &mut Context<'_>, @@ -386,9 +384,8 @@ where FramedServiceImplResponseInner, Poll>>, > { - #[project] match self.project() { - FramedServiceImplResponseInner::Connect(fut, handler) => match fut.poll(cx) { + FramedServiceImplResponseInnerProj::Connect(fut, handler) => match fut.poll(cx) { Poll::Ready(Ok(res)) => Either::Left(FramedServiceImplResponseInner::Handler( handler.new_service(res.state), Some(res.framed), @@ -397,7 +394,7 @@ where Poll::Pending => Either::Right(Poll::Pending), Poll::Ready(Err(e)) => Either::Right(Poll::Ready(Err(e.into()))), }, - FramedServiceImplResponseInner::Handler(fut, framed, out) => { + FramedServiceImplResponseInnerProj::Handler(fut, framed, out) => { match fut.poll(cx) { Poll::Ready(Ok(handler)) => { Either::Left(FramedServiceImplResponseInner::Dispatcher( @@ -408,7 +405,7 @@ where Poll::Ready(Err(e)) => Either::Right(Poll::Ready(Err(e.into()))), } } - FramedServiceImplResponseInner::Dispatcher(fut) => { + FramedServiceImplResponseInnerProj::Dispatcher(fut) => { Either::Right(fut.poll(cx)) } } diff --git a/actix-ioframe/tests/test_server.rs b/actix-ioframe/tests/test_server.rs index b1f7f301..9d3775b3 100644 --- a/actix-ioframe/tests/test_server.rs +++ b/actix-ioframe/tests/test_server.rs @@ -6,7 +6,7 @@ use actix_service::{fn_factory_with_config, fn_service, IntoService, Service}; use actix_testing::TestServer; use actix_utils::mpsc; use bytes::{Bytes, BytesMut}; -use futures::future::ok; +use futures_util::future::ok; use actix_ioframe::{Builder, Connect, FactoryBuilder}; diff --git a/actix-macros/.gitignore b/actix-macros/.gitignore new file mode 100644 index 00000000..b619655b --- /dev/null +++ b/actix-macros/.gitignore @@ -0,0 +1 @@ +/wip diff --git a/actix-macros/CHANGES.md b/actix-macros/CHANGES.md new file mode 100644 index 00000000..7b89882e --- /dev/null +++ b/actix-macros/CHANGES.md @@ -0,0 +1,9 @@ +# CHANGES + +## 0.1.2 - 2020-05-18 + +### Changed + +* Forward actix_rt::test arguments to test function [#127] + +[#127]: https://github.com/actix/actix-net/pull/127 diff --git a/actix-macros/Cargo.toml b/actix-macros/Cargo.toml index 8691f041..a8527673 100644 --- a/actix-macros/Cargo.toml +++ b/actix-macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "actix-macros" -version = "0.1.1" +version = "0.1.2" authors = ["Nikolay Kim "] description = "Actix runtime macros" repository = "https://github.com/actix/actix-net" @@ -8,14 +8,16 @@ documentation = "https://docs.rs/actix-macros/" categories = ["network-programming", "asynchronous"] license = "MIT/Apache-2.0" edition = "2018" -workspace = ".." [lib] proc-macro = true [dependencies] -quote = "=1.0.2" +quote = "1.0.3" syn = { version = "^1", features = ["full"] } [dev-dependencies] -actix-rt = { version = "1.0.0" } +actix-rt = "1.0" + +futures-util = { version = "0.3", default-features = false } +trybuild = "1" diff --git a/actix-macros/src/lib.rs b/actix-macros/src/lib.rs index b6a57b9d..04c374a5 100644 --- a/actix-macros/src/lib.rs +++ b/actix-macros/src/lib.rs @@ -55,12 +55,11 @@ pub fn main(_: TokenStream, item: TokenStream) -> TokenStream { /// ``` #[proc_macro_attribute] pub fn test(_: TokenStream, item: TokenStream) -> TokenStream { - let input = syn::parse_macro_input!(item as syn::ItemFn); - - let ret = &input.sig.output; - let name = &input.sig.ident; - let body = &input.block; + let mut input = syn::parse_macro_input!(item as syn::ItemFn); let attrs = &input.attrs; + let vis = &input.vis; + let sig = &mut input.sig; + let body = &input.block; let mut has_test_attr = false; for attr in attrs { @@ -69,7 +68,7 @@ pub fn test(_: TokenStream, item: TokenStream) -> TokenStream { } } - if input.sig.asyncness.is_none() { + if sig.asyncness.is_none() { return syn::Error::new_spanned( input.sig.fn_token, format!("only async fn is supported, {}", input.sig.ident), @@ -78,10 +77,12 @@ pub fn test(_: TokenStream, item: TokenStream) -> TokenStream { .into(); } + sig.asyncness = None; + let result = if has_test_attr { quote! { #(#attrs)* - fn #name() #ret { + #vis #sig { actix_rt::System::new("test") .block_on(async { #body }) } @@ -90,7 +91,7 @@ pub fn test(_: TokenStream, item: TokenStream) -> TokenStream { quote! { #[test] #(#attrs)* - fn #name() #ret { + #vis #sig { actix_rt::System::new("test") .block_on(async { #body }) } diff --git a/actix-macros/tests/trybuild.rs b/actix-macros/tests/trybuild.rs new file mode 100644 index 00000000..d944e3a2 --- /dev/null +++ b/actix-macros/tests/trybuild.rs @@ -0,0 +1,9 @@ +#[test] +fn compile_macros() { + let t = trybuild::TestCases::new(); + t.pass("tests/trybuild/main-01-basic.rs"); + t.compile_fail("tests/trybuild/main-02-only-async.rs"); + + t.pass("tests/trybuild/test-01-basic.rs"); + t.pass("tests/trybuild/test-02-keep-attrs.rs"); +} diff --git a/actix-macros/tests/trybuild/main-01-basic.rs b/actix-macros/tests/trybuild/main-01-basic.rs new file mode 100644 index 00000000..8bb86a81 --- /dev/null +++ b/actix-macros/tests/trybuild/main-01-basic.rs @@ -0,0 +1,4 @@ +#[actix_rt::main] +async fn main() { + println!("Hello world"); +} diff --git a/actix-macros/tests/trybuild/main-02-only-async.rs b/actix-macros/tests/trybuild/main-02-only-async.rs new file mode 100644 index 00000000..63c1b788 --- /dev/null +++ b/actix-macros/tests/trybuild/main-02-only-async.rs @@ -0,0 +1,4 @@ +#[actix_rt::main] +fn main() { + futures_util::future::ready(()).await +} diff --git a/actix-macros/tests/trybuild/main-02-only-async.stderr b/actix-macros/tests/trybuild/main-02-only-async.stderr new file mode 100644 index 00000000..e5e44492 --- /dev/null +++ b/actix-macros/tests/trybuild/main-02-only-async.stderr @@ -0,0 +1,14 @@ +error: only async fn is supported + --> $DIR/main-02-only-async.rs:2:1 + | +2 | fn main() { + | ^^ + +error[E0601]: `main` function not found in crate `$CRATE` + --> $DIR/main-02-only-async.rs:1:1 + | +1 | / #[actix_rt::main] +2 | | fn main() { +3 | | futures_util::future::ready(()).await +4 | | } + | |_^ consider adding a `main` function to `$DIR/tests/trybuild/main-02-only-async.rs` diff --git a/actix-macros/tests/trybuild/test-01-basic.rs b/actix-macros/tests/trybuild/test-01-basic.rs new file mode 100644 index 00000000..8339a969 --- /dev/null +++ b/actix-macros/tests/trybuild/test-01-basic.rs @@ -0,0 +1,6 @@ +#[actix_rt::test] +async fn my_test() { + assert!(true); +} + +fn main() {} diff --git a/actix-macros/tests/trybuild/test-02-keep-attrs.rs b/actix-macros/tests/trybuild/test-02-keep-attrs.rs new file mode 100644 index 00000000..22c98d55 --- /dev/null +++ b/actix-macros/tests/trybuild/test-02-keep-attrs.rs @@ -0,0 +1,7 @@ +#[actix_rt::test] +#[should_panic] +async fn my_test() { + todo!() +} + +fn main() {} diff --git a/actix-rt/CHANGES.md b/actix-rt/CHANGES.md index a95057c2..518a68ac 100644 --- a/actix-rt/CHANGES.md +++ b/actix-rt/CHANGES.md @@ -1,10 +1,27 @@ # Changes -## [TBD] - [TBD] +## [1.1.1] - 2020-04-30 -- Expose `System::is_set` to check if current system is running +### Fixed -- Add `Arbiter::local_join` associated function to get be able to `await` for spawned futures +* Fix memory leak due to [#94] (see [#129] for more detail) + +[#129]: https://github.com/actix/actix-net/issues/129 + +## [1.1.0] - 2020-04-08 + +**This version has been yanked.** + +### Added + +* Expose `System::is_set` to check if current system has ben started [#99] +* Add `Arbiter::is_running` to check if event loop is running [#124] +* Add `Arbiter::local_join` associated function + to get be able to `await` for spawned futures [#94] + +[#94]: https://github.com/actix/actix-net/pull/94 +[#99]: https://github.com/actix/actix-net/pull/99 +[#124]: https://github.com/actix/actix-net/pull/124 ## [1.0.0] - 2019-12-11 diff --git a/actix-rt/Cargo.toml b/actix-rt/Cargo.toml index a7918a99..9b1cd53f 100644 --- a/actix-rt/Cargo.toml +++ b/actix-rt/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "actix-rt" -version = "1.0.0" +version = "1.1.1" authors = ["Nikolay Kim "] description = "Actix runtime" keywords = ["network", "framework", "async", "futures"] @@ -18,7 +18,8 @@ path = "src/lib.rs" [dependencies] actix-macros = "0.1.0" actix-threadpool = "0.3" -futures-channel = { version = "0.3.1", default-features = false } -futures-util = { version = "0.3.1", default-features = false } +futures-channel = { version = "0.3.4", default-features = false } +futures-util = { version = "0.3.4", default-features = false, features = ["alloc"] } copyless = "0.1.4" +smallvec = "1" tokio = { version = "0.2.6", default-features = false, features = ["rt-core", "rt-util", "io-driver", "tcp", "uds", "udp", "time", "signal", "stream"] } diff --git a/actix-rt/src/arbiter.rs b/actix-rt/src/arbiter.rs index c8c49775..eff10ca3 100644 --- a/actix-rt/src/arbiter.rs +++ b/actix-rt/src/arbiter.rs @@ -8,20 +8,24 @@ use std::{fmt, thread}; use futures_channel::mpsc::{unbounded, UnboundedReceiver, UnboundedSender}; use futures_channel::oneshot::{channel, Canceled, Sender}; -use futures_util::{future::{self, Future, FutureExt}, stream::Stream}; +use futures_util::{ + future::{self, Future, FutureExt}, + stream::Stream, +}; use crate::runtime::Runtime; use crate::system::System; use copyless::BoxHelper; +use smallvec::SmallVec; pub use tokio::task::JoinHandle; thread_local!( static ADDR: RefCell> = RefCell::new(None); static RUNNING: Cell = Cell::new(false); static Q: RefCell>>>> = RefCell::new(Vec::new()); - static PENDING: RefCell>> = RefCell::new(Vec::new()); + static PENDING: RefCell; 8]>> = RefCell::new(SmallVec::new()); static STORAGE: RefCell>> = RefCell::new(HashMap::new()); ); @@ -86,6 +90,11 @@ impl Arbiter { }) } + /// Check if current arbiter is running. + pub fn is_running() -> bool { + RUNNING.with(|cell| cell.get()) + } + /// Stop arbiter from continuing it's event loop. pub fn stop(&self) { let _ = self.sender.unbounded_send(ArbiterCommand::Stop); @@ -173,15 +182,20 @@ impl Arbiter { RUNNING.with(move |cell| { if cell.get() { // Spawn the future on running executor - PENDING.with(move |cell| { - cell.borrow_mut().push(tokio::task::spawn_local(future)); - }) + let len = PENDING.with(move |cell| { + let mut p = cell.borrow_mut(); + p.push(tokio::task::spawn_local(future)); + p.len() + }); + if len > 7 { + // Before reaching the inline size + tokio::task::spawn_local(CleanupPending); + } } else { // Box the future and push it to the queue, this results in double boxing // because the executor boxes the future again, but works for now Q.with(move |cell| { - cell.borrow_mut() - .push(Pin::from(Box::alloc().init(future))) + cell.borrow_mut().push(Pin::from(Box::alloc().init(future))) }); } }); @@ -304,12 +318,36 @@ impl Arbiter { /// have completed. pub fn local_join() -> impl Future { PENDING.with(move |cell| { - let current = cell.replace(Vec::new()); + let current = cell.replace(SmallVec::new()); future::join_all(current).map(|_| ()) }) } } +/// Future used for cleaning-up already finished `JoinHandle`s +/// from the `PENDING` list so the vector doesn't grow indefinitely +struct CleanupPending; + +impl Future for CleanupPending { + type Output = (); + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + PENDING.with(move |cell| { + let mut pending = cell.borrow_mut(); + let mut i = 0; + while i != pending.len() { + if let Poll::Ready(_) = Pin::new(&mut pending[i]).poll(cx) { + pending.remove(i); + } else { + i += 1; + } + } + }); + + Poll::Ready(()) + } +} + struct ArbiterController { stop: Option>, rx: UnboundedReceiver, @@ -343,9 +381,15 @@ impl Future for ArbiterController { return Poll::Ready(()); } ArbiterCommand::Execute(fut) => { - PENDING.with(move |cell| { - cell.borrow_mut().push(tokio::task::spawn_local(fut)); + let len = PENDING.with(move |cell| { + let mut p = cell.borrow_mut(); + p.push(tokio::task::spawn_local(fut)); + p.len() }); + if len > 7 { + // Before reaching the inline size + tokio::task::spawn_local(CleanupPending); + } } ArbiterCommand::ExecuteFn(f) => { f.call_box(); diff --git a/actix-rt/src/system.rs b/actix-rt/src/system.rs index f89fe9f3..21264669 100644 --- a/actix-rt/src/system.rs +++ b/actix-rt/src/system.rs @@ -79,7 +79,7 @@ impl System { }) } - /// Check if current system is running. + /// Check if current system is set, i.e., as already been started. pub fn is_set() -> bool { CURRENT.with(|cell| cell.borrow().is_some()) } diff --git a/actix-rt/tests/wait_spawned.rs b/actix-rt/tests/integration_tests.rs similarity index 90% rename from actix-rt/tests/wait_spawned.rs rename to actix-rt/tests/integration_tests.rs index af5d0224..8e775bab 100644 --- a/actix-rt/tests/wait_spawned.rs +++ b/actix-rt/tests/integration_tests.rs @@ -1,5 +1,19 @@ use std::time::{Duration, Instant}; +#[test] +fn start_and_stop() { + actix_rt::System::new("start_and_stop").block_on(async move { + assert!( + actix_rt::Arbiter::is_running(), + "System doesn't seem to have started" + ); + }); + assert!( + !actix_rt::Arbiter::is_running(), + "System doesn't seem to have stopped" + ); +} + #[test] fn await_for_timer() { let time = Duration::from_secs(2); diff --git a/actix-server/CHANGES.md b/actix-server/CHANGES.md index 127e7262..067adcd6 100644 --- a/actix-server/CHANGES.md +++ b/actix-server/CHANGES.md @@ -1,5 +1,13 @@ # Changes +## [1.0.3] - 2020-05-19 + +### Changed + +* Replace deprecated `net2` crate with `socket2` [#140] + +[#140]: https://github.com/actix/actix-net/pull/140 + ## [1.0.2] - 2020-02-26 ### Fixed diff --git a/actix-server/Cargo.toml b/actix-server/Cargo.toml index eef518e6..7d584aba 100644 --- a/actix-server/Cargo.toml +++ b/actix-server/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "actix-server" -version = "1.0.2" +version = "1.0.3" authors = ["Nikolay Kim "] description = "Actix server - General purpose tcp server" keywords = ["network", "framework", "async", "futures"] @@ -9,7 +9,7 @@ repository = "https://github.com/actix/actix-net.git" documentation = "https://docs.rs/actix-server/" categories = ["network-programming", "asynchronous"] license = "MIT/Apache-2.0" -exclude = [".gitignore", ".travis.yml", ".cargo/config", "appveyor.yml"] +exclude = [".gitignore", ".cargo/config"] edition = "2018" workspace = ".." @@ -29,8 +29,9 @@ actix-utils = "1.0.4" log = "0.4" num_cpus = "1.11" mio = "0.6.19" -net2 = "0.2" -futures = "0.3.1" +socket2 = "0.3" +futures-channel = { version = "0.3.4", default-features = false } +futures-util = { version = "0.3.4", default-features = false, features = ["sink"] } slab = "0.4" # unix domain sockets @@ -40,4 +41,4 @@ mio-uds = { version = "0.6.7" } [dev-dependencies] bytes = "0.5" env_logger = "0.7" -actix-testing = "1.0.0" \ No newline at end of file +actix-testing = "1.0.0" diff --git a/actix-server/src/builder.rs b/actix-server/src/builder.rs index ecc3e4e7..2e8ae30e 100644 --- a/actix-server/src/builder.rs +++ b/actix-server/src/builder.rs @@ -6,13 +6,13 @@ use std::{io, mem, net}; use actix_rt::net::TcpStream; use actix_rt::time::{delay_until, Instant}; use actix_rt::{spawn, System}; -use futures::channel::mpsc::{unbounded, UnboundedReceiver}; -use futures::channel::oneshot; -use futures::future::ready; -use futures::stream::FuturesUnordered; -use futures::{ready, Future, FutureExt, Stream, StreamExt}; +use futures_channel::mpsc::{unbounded, UnboundedReceiver}; +use futures_channel::oneshot; +use futures_util::future::ready; +use futures_util::stream::FuturesUnordered; +use futures_util::{future::Future, ready, stream::Stream, FutureExt, StreamExt}; use log::{error, info}; -use net2::TcpBuilder; +use socket2::{Domain, Protocol, Socket, Type}; use crate::accept::{AcceptLoop, AcceptNotify, Command}; use crate::config::{ConfiguredService, ServiceConfig}; @@ -381,7 +381,7 @@ impl ServerBuilder { .await; System::current().stop(); } - .boxed(), + .boxed(), ); } ready(()) @@ -487,11 +487,13 @@ pub(super) fn bind_addr( } fn create_tcp_listener(addr: net::SocketAddr, backlog: i32) -> io::Result { - let builder = match addr { - net::SocketAddr::V4(_) => TcpBuilder::new_v4()?, - net::SocketAddr::V6(_) => TcpBuilder::new_v6()?, + let domain = match addr { + net::SocketAddr::V4(_) => Domain::ipv4(), + net::SocketAddr::V6(_) => Domain::ipv6(), }; - builder.reuse_address(true)?; - builder.bind(addr)?; - Ok(builder.listen(backlog)?) + let socket = Socket::new(domain, Type::stream(), Some(Protocol::tcp()))?; + socket.set_reuse_address(true)?; + socket.bind(&addr.into())?; + socket.listen(backlog)?; + Ok(socket.into_tcp_listener()) } diff --git a/actix-server/src/config.rs b/actix-server/src/config.rs index 464635b1..65f19884 100644 --- a/actix-server/src/config.rs +++ b/actix-server/src/config.rs @@ -4,7 +4,7 @@ use std::{fmt, io, net}; use actix_rt::net::TcpStream; use actix_service as actix; use actix_utils::counter::CounterGuard; -use futures::future::{ok, Future, FutureExt, LocalBoxFuture}; +use futures_util::future::{ok, Future, FutureExt, LocalBoxFuture}; use log::error; use super::builder::bind_addr; @@ -218,7 +218,7 @@ impl ServiceRuntime { // let name = name.to_owned(); if let Some(token) = self.names.get(name) { self.services.insert( - token.clone(), + *token, Box::new(ServiceFactory { inner: service.into_factory(), }), diff --git a/actix-server/src/server.rs b/actix-server/src/server.rs index 6ba2547f..b29a9e02 100644 --- a/actix-server/src/server.rs +++ b/actix-server/src/server.rs @@ -3,9 +3,9 @@ use std::io; use std::pin::Pin; use std::task::{Context, Poll}; -use futures::channel::mpsc::UnboundedSender; -use futures::channel::oneshot; -use futures::FutureExt; +use futures_channel::mpsc::UnboundedSender; +use futures_channel::oneshot; +use futures_util::FutureExt; use crate::builder::ServerBuilder; use crate::signals::Signal; diff --git a/actix-server/src/service.rs b/actix-server/src/service.rs index c46126a8..bf429185 100644 --- a/actix-server/src/service.rs +++ b/actix-server/src/service.rs @@ -6,8 +6,8 @@ use std::time::Duration; use actix_rt::spawn; use actix_service::{self as actix, Service, ServiceFactory as ActixServiceFactory}; use actix_utils::counter::CounterGuard; -use futures::future::{err, ok, LocalBoxFuture, Ready}; -use futures::{FutureExt, TryFutureExt}; +use futures_util::future::{err, ok, LocalBoxFuture, Ready}; +use futures_util::{FutureExt, TryFutureExt}; use log::error; use super::Token; diff --git a/actix-server/src/signals.rs b/actix-server/src/signals.rs index db226585..b6339621 100644 --- a/actix-server/src/signals.rs +++ b/actix-server/src/signals.rs @@ -3,7 +3,7 @@ use std::io; use std::pin::Pin; use std::task::{Context, Poll}; -use futures::future::lazy; +use futures_util::future::lazy; use crate::server::Server; diff --git a/actix-server/src/worker.rs b/actix-server/src/worker.rs index f51fd310..4ae3e4f3 100644 --- a/actix-server/src/worker.rs +++ b/actix-server/src/worker.rs @@ -7,10 +7,10 @@ use std::time; use actix_rt::time::{delay_until, Delay, Instant}; use actix_rt::{spawn, Arbiter}; use actix_utils::counter::Counter; -use futures::channel::mpsc::{unbounded, UnboundedReceiver, UnboundedSender}; -use futures::channel::oneshot; -use futures::future::{join_all, LocalBoxFuture, MapOk}; -use futures::{Future, FutureExt, Stream, TryFutureExt}; +use futures_channel::mpsc::{unbounded, UnboundedReceiver, UnboundedSender}; +use futures_channel::oneshot; +use futures_util::future::{join_all, LocalBoxFuture, MapOk}; +use futures_util::{future::Future, stream::Stream, FutureExt, TryFutureExt}; use log::{error, info, trace}; use crate::accept::AcceptNotify; diff --git a/actix-server/tests/test_server.rs b/actix-server/tests/test_server.rs index c5aa70bc..ce309c94 100644 --- a/actix-server/tests/test_server.rs +++ b/actix-server/tests/test_server.rs @@ -4,15 +4,15 @@ use std::{net, thread, time}; use actix_server::Server; use actix_service::fn_service; -use futures::future::{lazy, ok}; -use net2::TcpBuilder; +use futures_util::future::{lazy, ok}; +use socket2::{Domain, Protocol, Socket, Type}; fn unused_addr() -> net::SocketAddr { let addr: net::SocketAddr = "127.0.0.1:0".parse().unwrap(); - let socket = TcpBuilder::new_v4().unwrap(); - socket.bind(&addr).unwrap(); - socket.reuse_address(true).unwrap(); - let tcp = socket.to_tcp_listener().unwrap(); + let socket = Socket::new(Domain::ipv4(), Type::stream(), Some(Protocol::tcp())).unwrap(); + socket.bind(&addr.into()).unwrap(); + socket.set_reuse_address(true).unwrap(); + let tcp = socket.into_tcp_listener(); tcp.local_addr().unwrap() } @@ -71,7 +71,7 @@ fn test_start() { use actix_codec::{BytesCodec, Framed}; use actix_rt::net::TcpStream; use bytes::Bytes; - use futures::SinkExt; + use futures_util::sink::SinkExt; use std::io::Read; let addr = unused_addr(); @@ -83,12 +83,10 @@ fn test_start() { .backlog(100) .disable_signals() .bind("test", addr, move || { - fn_service(|io: TcpStream| { - async move { - let mut f = Framed::new(io, BytesCodec); - f.send(Bytes::from_static(b"test")).await.unwrap(); - Ok::<_, ()>(()) - } + fn_service(|io: TcpStream| async move { + let mut f = Framed::new(io, BytesCodec); + f.send(Bytes::from_static(b"test")).await.unwrap(); + Ok::<_, ()>(()) }) }) .unwrap() diff --git a/actix-service/Cargo.toml b/actix-service/Cargo.toml index 939ed178..cb2b2cdb 100644 --- a/actix-service/Cargo.toml +++ b/actix-service/Cargo.toml @@ -17,7 +17,7 @@ path = "src/lib.rs" [dependencies] futures-util = "0.3.1" -pin-project = "0.4.6" +pin-project = "0.4.17" [dev-dependencies] actix-rt = "1.0.0" diff --git a/actix-service/benches/and_then.rs b/actix-service/benches/and_then.rs index 58c00b6c..1ae46d4c 100644 --- a/actix-service/benches/and_then.rs +++ b/actix-service/benches/and_then.rs @@ -81,7 +81,7 @@ where state: State, } -#[pin_project::pin_project] +#[pin_project::pin_project(project = StateProj)] enum State where A: Service, @@ -99,13 +99,11 @@ where { type Output = Result; - #[pin_project::project] fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { let mut this = self.as_mut().project(); - #[project] match this.state.as_mut().project() { - State::A(fut, b) => match fut.poll(cx)? { + StateProj::A(fut, b) => match fut.poll(cx)? { Poll::Ready(res) => { let b = b.take().unwrap(); this.state.set(State::Empty); // drop fut A @@ -115,11 +113,11 @@ where } Poll::Pending => Poll::Pending, }, - State::B(fut) => fut.poll(cx).map(|r| { + StateProj::B(fut) => fut.poll(cx).map(|r| { this.state.set(State::Empty); r }), - State::Empty => panic!("future must not be polled after it returned `Poll::Ready`"), + StateProj::Empty => panic!("future must not be polled after it returned `Poll::Ready`"), } } } @@ -179,7 +177,7 @@ where state: StateRC, } - #[pin_project::pin_project] + #[pin_project::pin_project(project = StateRCProj)] enum StateRC where A: Service, @@ -196,14 +194,12 @@ where B: Service, { type Output = Result; - - #[pin_project::project] + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { let mut this = self.as_mut().project(); - - #[project] + match this.state.as_mut().project() { - StateRC::A(fut, b) => match fut.poll(cx)? { + StateRCProj::A(fut, b) => match fut.poll(cx)? { Poll::Ready(res) => { let b = b.take().unwrap(); this.state.set(StateRC::Empty); // drop fut A @@ -213,11 +209,11 @@ where } Poll::Pending => Poll::Pending, }, - StateRC::B(fut) => fut.poll(cx).map(|r| { + StateRCProj::B(fut) => fut.poll(cx).map(|r| { this.state.set(StateRC::Empty); r }), - StateRC::Empty => panic!("future must not be polled after it returned `Poll::Ready`"), + StateRCProj::Empty => panic!("future must not be polled after it returned `Poll::Ready`"), } } } diff --git a/actix-service/src/and_then.rs b/actix-service/src/and_then.rs index 01840c18..1d7e216d 100644 --- a/actix-service/src/and_then.rs +++ b/actix-service/src/and_then.rs @@ -67,7 +67,7 @@ where state: State, } -#[pin_project::pin_project] +#[pin_project::pin_project(project = StateProj)] enum State where A: Service, @@ -85,13 +85,11 @@ where { type Output = Result; - #[pin_project::project] fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { let mut this = self.as_mut().project(); - #[project] match this.state.as_mut().project() { - State::A(fut, b) => match fut.poll(cx)? { + StateProj::A(fut, b) => match fut.poll(cx)? { Poll::Ready(res) => { let mut b = b.take().unwrap(); this.state.set(State::Empty); // drop fut A @@ -101,11 +99,11 @@ where } Poll::Pending => Poll::Pending, }, - State::B(fut) => fut.poll(cx).map(|r| { + StateProj::B(fut) => fut.poll(cx).map(|r| { this.state.set(State::Empty); r }), - State::Empty => panic!("future must not be polled after it returned `Poll::Ready`"), + StateProj::Empty => panic!("future must not be polled after it returned `Poll::Ready`"), } } } diff --git a/actix-service/src/and_then_apply_fn.rs b/actix-service/src/and_then_apply_fn.rs index 07f3b50d..de0cfac9 100644 --- a/actix-service/src/and_then_apply_fn.rs +++ b/actix-service/src/and_then_apply_fn.rs @@ -98,7 +98,7 @@ where state: State, } -#[pin_project::pin_project] +#[pin_project::pin_project(project = StateProj)] enum State where A: Service, @@ -123,13 +123,11 @@ where { type Output = Result; - #[pin_project::project] fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { let mut this = self.as_mut().project(); - #[project] match this.state.as_mut().project() { - State::A(fut, b) => match fut.poll(cx)? { + StateProj::A(fut, b) => match fut.poll(cx)? { Poll::Ready(res) => { let mut b = b.take().unwrap(); this.state.set(State::Empty); @@ -140,11 +138,11 @@ where } Poll::Pending => Poll::Pending, }, - State::B(fut) => fut.poll(cx).map(|r| { + StateProj::B(fut) => fut.poll(cx).map(|r| { this.state.set(State::Empty); r }), - State::Empty => panic!("future must not be polled after it returned `Poll::Ready`"), + StateProj::Empty => panic!("future must not be polled after it returned `Poll::Ready`"), } } } diff --git a/actix-service/src/apply_cfg.rs b/actix-service/src/apply_cfg.rs index 5c69b813..cee7b8c7 100644 --- a/actix-service/src/apply_cfg.rs +++ b/actix-service/src/apply_cfg.rs @@ -177,7 +177,7 @@ where state: State, } -#[pin_project::pin_project] +#[pin_project::pin_project(project = StateProj)] enum State where T: ServiceFactory, @@ -200,20 +200,18 @@ where { type Output = Result; - #[pin_project::project] fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { let mut this = self.as_mut().project(); - #[project] match this.state.as_mut().project() { - State::A(fut) => match fut.poll(cx)? { + StateProj::A(fut) => match fut.poll(cx)? { Poll::Pending => Poll::Pending, Poll::Ready(srv) => { this.state.set(State::B(srv)); self.poll(cx) } }, - State::B(srv) => match srv.poll_ready(cx)? { + StateProj::B(srv) => match srv.poll_ready(cx)? { Poll::Ready(_) => { let fut = (this.store.get_mut().1)(this.cfg.take().unwrap(), srv); this.state.set(State::C(fut)); @@ -221,7 +219,7 @@ where } Poll::Pending => Poll::Pending, }, - State::C(fut) => fut.poll(cx), + StateProj::C(fut) => fut.poll(cx), } } } diff --git a/actix-service/src/then.rs b/actix-service/src/then.rs index 53ff1753..1286e742 100644 --- a/actix-service/src/then.rs +++ b/actix-service/src/then.rs @@ -66,7 +66,7 @@ where state: State, } -#[pin_project::pin_project] +#[pin_project::pin_project(project = StateProj)] enum State where A: Service, @@ -84,13 +84,11 @@ where { type Output = Result; - #[pin_project::project] fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { let mut this = self.as_mut().project(); - #[project] match this.state.as_mut().project() { - State::A(fut, b) => match fut.poll(cx) { + StateProj::A(fut, b) => match fut.poll(cx) { Poll::Ready(res) => { let mut b = b.take().unwrap(); this.state.set(State::Empty); // drop fut A @@ -100,11 +98,11 @@ where } Poll::Pending => Poll::Pending, }, - State::B(fut) => fut.poll(cx).map(|r| { + StateProj::B(fut) => fut.poll(cx).map(|r| { this.state.set(State::Empty); r }), - State::Empty => panic!("future must not be polled after it returned `Poll::Ready`"), + StateProj::Empty => panic!("future must not be polled after it returned `Poll::Ready`"), } } } diff --git a/actix-service/src/transform.rs b/actix-service/src/transform.rs index 27704986..dc55f533 100644 --- a/actix-service/src/transform.rs +++ b/actix-service/src/transform.rs @@ -211,7 +211,7 @@ where state: ApplyTransformFutureState, } -#[pin_project::pin_project] +#[pin_project::pin_project(project = ApplyTransformFutureStateProj)] pub enum ApplyTransformFutureState where S: ServiceFactory, @@ -228,13 +228,11 @@ where { type Output = Result; - #[pin_project::project] fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { let mut this = self.as_mut().project(); - #[project] match this.state.as_mut().project() { - ApplyTransformFutureState::A(fut) => match fut.poll(cx)? { + ApplyTransformFutureStateProj::A(fut) => match fut.poll(cx)? { Poll::Ready(srv) => { let fut = this.store.0.new_transform(srv); this.state.set(ApplyTransformFutureState::B(fut)); @@ -242,7 +240,7 @@ where } Poll::Pending => Poll::Pending, }, - ApplyTransformFutureState::B(fut) => fut.poll(cx), + ApplyTransformFutureStateProj::B(fut) => fut.poll(cx), } } } diff --git a/actix-testing/CHANGES.md b/actix-testing/CHANGES.md index cc37a085..86a79ed7 100644 --- a/actix-testing/CHANGES.md +++ b/actix-testing/CHANGES.md @@ -1,5 +1,11 @@ # Changes +## [1.0.1] - 2020-05-19 + +* Replace deprecated `net2` crate with `socket2` + +* Remove unused `futures` dependency + ## [1.0.0] - 2019-12-11 * Update actix-server to 1.0.0 diff --git a/actix-testing/Cargo.toml b/actix-testing/Cargo.toml index 6c0f96c7..8646440d 100644 --- a/actix-testing/Cargo.toml +++ b/actix-testing/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "actix-testing" -version = "1.0.0" +version = "1.0.1" authors = ["Nikolay Kim "] description = "Actix testing utils" keywords = ["network", "framework", "async", "futures"] @@ -11,6 +11,7 @@ categories = ["network-programming", "asynchronous"] license = "MIT/Apache-2.0" edition = "2018" workspace = ".." +readme = "README.md" [lib] name = "actix_testing" @@ -23,5 +24,4 @@ actix-server = "1.0.0" actix-service = "1.0.0" log = "0.4" -net2 = "0.2" -futures = "0.3.1" +socket2 = "0.3" diff --git a/actix-testing/src/lib.rs b/actix-testing/src/lib.rs index c1e192e1..5b0113e1 100644 --- a/actix-testing/src/lib.rs +++ b/actix-testing/src/lib.rs @@ -7,7 +7,7 @@ use std::{net, thread}; use actix_rt::{net::TcpStream, System}; use actix_server::{Server, ServerBuilder, ServiceFactory}; -use net2::TcpBuilder; +use socket2::{Domain, Protocol, Socket, Type}; #[cfg(not(test))] // Work around for rust-lang/rust#62127 pub use actix_macros::test; @@ -110,10 +110,11 @@ impl TestServer { /// Get firat available unused local address pub fn unused_addr() -> net::SocketAddr { let addr: net::SocketAddr = "127.0.0.1:0".parse().unwrap(); - let socket = TcpBuilder::new_v4().unwrap(); - socket.bind(&addr).unwrap(); - socket.reuse_address(true).unwrap(); - let tcp = socket.to_tcp_listener().unwrap(); + let socket = + Socket::new(Domain::ipv4(), Type::stream(), Some(Protocol::tcp())).unwrap(); + socket.bind(&addr.into()).unwrap(); + socket.set_reuse_address(true).unwrap(); + let tcp = socket.into_tcp_listener(); tcp.local_addr().unwrap() } } diff --git a/actix-threadpool/CHANGES.md b/actix-threadpool/CHANGES.md index dd10210f..6b4cd429 100644 --- a/actix-threadpool/CHANGES.md +++ b/actix-threadpool/CHANGES.md @@ -1,5 +1,13 @@ # Changes +## [0.3.2] - 2020-05-20 + +## Added + +* Implement `std::error::Error` for `BlockingError` [#120] + +[#120]: https://github.com/actix/actix-net/pull/120 + ## [0.3.1] - 2019-12-12 ### Changed diff --git a/actix-threadpool/Cargo.toml b/actix-threadpool/Cargo.toml index 36f9acfb..5b21ba45 100644 --- a/actix-threadpool/Cargo.toml +++ b/actix-threadpool/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "actix-threadpool" -version = "0.3.1" +version = "0.3.2" authors = ["Nikolay Kim "] description = "Actix thread pool for sync code" keywords = ["actix", "network", "framework", "async", "futures"] diff --git a/actix-threadpool/src/lib.rs b/actix-threadpool/src/lib.rs index beead547..08b563ef 100644 --- a/actix-threadpool/src/lib.rs +++ b/actix-threadpool/src/lib.rs @@ -48,6 +48,8 @@ pub enum BlockingError { Canceled, } +impl std::error::Error for BlockingError {} + /// Execute blocking function on a thread pool, returns future that resolves /// to result of the function execution. pub fn run(f: F) -> CpuFuture diff --git a/actix-tls/Cargo.toml b/actix-tls/Cargo.toml index 58baadc1..0d235e22 100644 --- a/actix-tls/Cargo.toml +++ b/actix-tls/Cargo.toml @@ -38,7 +38,7 @@ actix-utils = "1.0.0" actix-rt = "1.0.0" derive_more = "0.99.2" either = "1.5.2" -futures = "0.3.1" +futures-util = { version = "0.3.4", default-features = false } log = "0.4" # openssl diff --git a/actix-tls/src/nativetls.rs b/actix-tls/src/nativetls.rs index 8b2c7cee..a4780db1 100644 --- a/actix-tls/src/nativetls.rs +++ b/actix-tls/src/nativetls.rs @@ -4,7 +4,7 @@ use std::task::{Context, Poll}; use actix_codec::{AsyncRead, AsyncWrite}; use actix_service::{Service, ServiceFactory}; use actix_utils::counter::Counter; -use futures::future::{self, FutureExt, LocalBoxFuture, TryFutureExt}; +use futures_util::future::{self, FutureExt, LocalBoxFuture, TryFutureExt}; pub use native_tls::Error; pub use tokio_tls::{TlsAcceptor, TlsStream}; diff --git a/actix-tls/src/openssl.rs b/actix-tls/src/openssl.rs index 3da8bfc6..3b98e2fe 100644 --- a/actix-tls/src/openssl.rs +++ b/actix-tls/src/openssl.rs @@ -9,7 +9,7 @@ pub use tokio_openssl::{HandshakeError, SslStream}; use actix_codec::{AsyncRead, AsyncWrite}; use actix_service::{Service, ServiceFactory}; use actix_utils::counter::{Counter, CounterGuard}; -use futures::future::{ok, FutureExt, LocalBoxFuture, Ready}; +use futures_util::future::{ok, FutureExt, LocalBoxFuture, Ready}; use crate::MAX_CONN_COUNTER; @@ -105,7 +105,7 @@ impl Future for AcceptorServiceResponse { type Output = Result, HandshakeError>; fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let io = futures::ready!(Pin::new(&mut self.fut).poll(cx))?; + let io = futures_util::ready!(Pin::new(&mut self.fut).poll(cx))?; Poll::Ready(Ok(io)) } } diff --git a/actix-tls/src/rustls.rs b/actix-tls/src/rustls.rs index b71e22a1..4546c24b 100644 --- a/actix-tls/src/rustls.rs +++ b/actix-tls/src/rustls.rs @@ -8,7 +8,7 @@ use std::task::{Context, Poll}; use actix_codec::{AsyncRead, AsyncWrite}; use actix_service::{Service, ServiceFactory}; use actix_utils::counter::{Counter, CounterGuard}; -use futures::future::{ok, Ready}; +use futures_util::future::{ok, Ready}; use tokio_rustls::{Accept, TlsAcceptor}; pub use rust_tls::{ServerConfig, Session}; @@ -108,7 +108,7 @@ impl Future for AcceptorServiceFut { fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { let this = self.get_mut(); - let res = futures::ready!(Pin::new(&mut this.fut).poll(cx)); + let res = futures_util::ready!(Pin::new(&mut this.fut).poll(cx)); match res { Ok(io) => Poll::Ready(Ok(io)), Err(e) => Poll::Ready(Err(e)), diff --git a/actix-tracing/Cargo.toml b/actix-tracing/Cargo.toml index 055cd11c..a8782361 100644 --- a/actix-tracing/Cargo.toml +++ b/actix-tracing/Cargo.toml @@ -17,7 +17,7 @@ path = "src/lib.rs" [dependencies] actix-service = "1.0.4" -futures-util = "0.3.1" +futures-util = { version = "0.3.4", default-features = false } tracing = "0.1" tracing-futures = "0.2" diff --git a/actix-utils/Cargo.toml b/actix-utils/Cargo.toml index 62207b36..f32ad5b5 100644 --- a/actix-utils/Cargo.toml +++ b/actix-utils/Cargo.toml @@ -22,7 +22,9 @@ actix-codec = "0.2.0" bitflags = "1.2" bytes = "0.5.3" either = "1.5.3" -futures = "0.3.1" -pin-project = "0.4.6" +futures-channel = { version = "0.3.4", default-features = false } +futures-sink = { version = "0.3.4", default-features = false } +futures-util = { version = "0.3.4", default-features = false } +pin-project = "0.4.17" log = "0.4" slab = "0.4" diff --git a/actix-utils/src/condition.rs b/actix-utils/src/condition.rs index 097034da..fe459cf7 100644 --- a/actix-utils/src/condition.rs +++ b/actix-utils/src/condition.rs @@ -96,7 +96,7 @@ impl Drop for Waiter { #[cfg(test)] mod tests { use super::*; - use futures::future::lazy; + use futures_util::future::lazy; #[actix_rt::test] async fn test_condition() { diff --git a/actix-utils/src/either.rs b/actix-utils/src/either.rs index 0aeecf89..53d6e86e 100644 --- a/actix-utils/src/either.rs +++ b/actix-utils/src/either.rs @@ -3,7 +3,7 @@ use std::pin::Pin; use std::task::{Context, Poll}; use actix_service::{Service, ServiceFactory}; -use futures::{future, ready, Future}; +use futures_util::{future, ready, future::Future}; /// Combine two different service types into a single type. /// diff --git a/actix-utils/src/framed.rs b/actix-utils/src/framed.rs index 9def5992..1663db9d 100644 --- a/actix-utils/src/framed.rs +++ b/actix-utils/src/framed.rs @@ -6,7 +6,7 @@ use std::{fmt, mem}; use actix_codec::{AsyncRead, AsyncWrite, Decoder, Encoder, Framed}; use actix_service::{IntoService, Service}; -use futures::{Future, FutureExt, Stream}; +use futures_util::{future::Future, FutureExt, stream::Stream}; use log::debug; use crate::mpsc; diff --git a/actix-utils/src/inflight.rs b/actix-utils/src/inflight.rs index 3f547db2..f07e4592 100644 --- a/actix-utils/src/inflight.rs +++ b/actix-utils/src/inflight.rs @@ -4,7 +4,7 @@ use std::pin::Pin; use std::task::{Context, Poll}; use actix_service::{IntoService, Service, Transform}; -use futures::future::{ok, Ready}; +use futures_util::future::{ok, Ready}; use super::counter::{Counter, CounterGuard}; @@ -116,7 +116,7 @@ mod tests { use super::*; use actix_service::{apply, fn_factory, Service, ServiceFactory}; - use futures::future::{lazy, ok, FutureExt, LocalBoxFuture}; + use futures_util::future::{lazy, ok, FutureExt, LocalBoxFuture}; struct SleepService(Duration); diff --git a/actix-utils/src/keepalive.rs b/actix-utils/src/keepalive.rs index 9d4f8712..4413dcd5 100644 --- a/actix-utils/src/keepalive.rs +++ b/actix-utils/src/keepalive.rs @@ -7,7 +7,7 @@ use std::time::Duration; use actix_rt::time::{delay_until, Delay, Instant}; use actix_service::{Service, ServiceFactory}; -use futures::future::{ok, Ready}; +use futures_util::future::{ok, Ready}; use super::time::{LowResTime, LowResTimeService}; diff --git a/actix-utils/src/mpsc.rs b/actix-utils/src/mpsc.rs index 07014835..531c9684 100644 --- a/actix-utils/src/mpsc.rs +++ b/actix-utils/src/mpsc.rs @@ -6,7 +6,8 @@ use std::fmt; use std::pin::Pin; use std::task::{Context, Poll}; -use futures::{Sink, Stream}; +use futures_sink::Sink; +use futures_util::stream::Stream; use crate::cell::Cell; use crate::task::LocalWaker; @@ -180,8 +181,8 @@ impl SendError { #[cfg(test)] mod tests { use super::*; - use futures::future::lazy; - use futures::{Stream, StreamExt}; + use futures_util::future::lazy; + use futures_util::{stream::Stream, StreamExt}; #[actix_rt::test] async fn test_mpsc() { diff --git a/actix-utils/src/oneshot.rs b/actix-utils/src/oneshot.rs index 533167c9..9945e5d3 100644 --- a/actix-utils/src/oneshot.rs +++ b/actix-utils/src/oneshot.rs @@ -3,7 +3,7 @@ use std::future::Future; use std::pin::Pin; use std::task::{Context, Poll}; -pub use futures::channel::oneshot::Canceled; +pub use futures_channel::oneshot::Canceled; use slab::Slab; use crate::cell::Cell; @@ -253,7 +253,7 @@ impl Future for PReceiver { #[cfg(test)] mod tests { use super::*; - use futures::future::lazy; + use futures_util::future::lazy; #[actix_rt::test] async fn test_oneshot() { diff --git a/actix-utils/src/order.rs b/actix-utils/src/order.rs index 7dd4e2fc..ba589f30 100644 --- a/actix-utils/src/order.rs +++ b/actix-utils/src/order.rs @@ -8,7 +8,7 @@ use std::rc::Rc; use std::task::{Context, Poll}; use actix_service::{IntoService, Service, Transform}; -use futures::future::{ok, Ready}; +use futures_util::future::{ok, Ready}; use crate::oneshot; use crate::task::LocalWaker; @@ -210,8 +210,8 @@ mod tests { use super::*; use actix_service::Service; - use futures::channel::oneshot; - use futures::future::{lazy, poll_fn, FutureExt, LocalBoxFuture}; + use futures_channel::oneshot; + use futures_util::future::{lazy, poll_fn, FutureExt, LocalBoxFuture}; struct Srv; diff --git a/actix-utils/src/stream.rs b/actix-utils/src/stream.rs index b7f008e4..90df8c2f 100644 --- a/actix-utils/src/stream.rs +++ b/actix-utils/src/stream.rs @@ -3,7 +3,7 @@ use std::pin::Pin; use std::task::{Context, Poll}; use actix_service::{IntoService, Service}; -use futures::{FutureExt, Stream}; +use futures_util::{FutureExt, stream::Stream}; use crate::mpsc; diff --git a/actix-utils/src/time.rs b/actix-utils/src/time.rs index 49d6283a..c7bfa922 100644 --- a/actix-utils/src/time.rs +++ b/actix-utils/src/time.rs @@ -4,7 +4,7 @@ use std::time::{self, Duration, Instant}; use actix_rt::time::delay_for; use actix_service::{Service, ServiceFactory}; -use futures::future::{ok, ready, FutureExt, Ready}; +use futures_util::future::{ok, ready, FutureExt, Ready}; use super::cell::Cell; diff --git a/actix-utils/src/timeout.rs b/actix-utils/src/timeout.rs index cb8c24b4..83fbb84f 100644 --- a/actix-utils/src/timeout.rs +++ b/actix-utils/src/timeout.rs @@ -10,7 +10,7 @@ use std::{fmt, time}; use actix_rt::time::{delay_for, Delay}; use actix_service::{IntoService, Service, Transform}; -use futures::future::{ok, Ready}; +use futures_util::future::{ok, Ready}; /// Applies a timeout to requests. #[derive(Debug)] @@ -183,7 +183,7 @@ mod tests { use super::*; use actix_service::{apply, fn_factory, Service, ServiceFactory}; - use futures::future::{ok, FutureExt, LocalBoxFuture}; + use futures_util::future::{ok, FutureExt, LocalBoxFuture}; struct SleepService(Duration); diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 00000000..d54a4f9a --- /dev/null +++ b/codecov.yml @@ -0,0 +1,14 @@ +coverage: + status: + project: + default: + threshold: 10% # make CI green + patch: + default: + threshold: 10% # make CI green + +ignore: # ignore codecoverage on following paths + - "examples" + - ".github" + - "**/*.md" + - "**/*.toml" diff --git a/examples/basic.rs b/examples/basic.rs index 5ff109d2..3de6d212 100644 --- a/examples/basic.rs +++ b/examples/basic.rs @@ -11,7 +11,7 @@ use actix_codec::{AsyncRead, AsyncWrite}; use actix_rt::System; use actix_server::{Io, Server}; use actix_service::{service_fn, NewService}; -use futures::{future, Future}; +use futures_util::{future, Future}; use openssl::ssl::{SslAcceptor, SslFiletype, SslMethod}; use tokio_openssl::SslAcceptorExt; diff --git a/examples/ssl.rs b/examples/ssl.rs index b7b70f1d..d15ed77a 100644 --- a/examples/ssl.rs +++ b/examples/ssl.rs @@ -7,7 +7,7 @@ use std::sync::{ use actix_rt::System; use actix_server::{ssl, Server}; use actix_service::NewService; -use futures::future; +use futures_util::future; use openssl::ssl::{SslAcceptor, SslFiletype, SslMethod}; #[derive(Debug)] diff --git a/router/src/url.rs b/router/src/url.rs index 1c068199..189a9e80 100644 --- a/router/src/url.rs +++ b/router/src/url.rs @@ -31,7 +31,7 @@ fn set_bit(array: &mut [u8], ch: u8) { } thread_local! { - static DEFAULT_QUOTER: Quoter = { Quoter::new(b"@:", b"/+") }; + static DEFAULT_QUOTER: Quoter = Quoter::new(b"@:", b"/+"); } #[derive(Default, Clone, Debug)] diff --git a/string/CHANGES.md b/string/CHANGES.md index 53ab9c7a..030c3cd5 100644 --- a/string/CHANGES.md +++ b/string/CHANGES.md @@ -1,5 +1,9 @@ # Changes +## [0.1.5] - 2020-03-30 + +* Serde support + ## [0.1.4] - 2020-01-14 * Fix `AsRef` impl diff --git a/string/Cargo.toml b/string/Cargo.toml index 0031ea5b..cafbaf80 100644 --- a/string/Cargo.toml +++ b/string/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bytestring" -version = "0.1.4" +version = "0.1.5" authors = ["Nikolay Kim "] description = "A UTF-8 encoded string with Bytes as a storage" keywords = ["actix"] @@ -16,3 +16,7 @@ path = "src/lib.rs" [dependencies] bytes = "0.5.3" +serde = { version = "1.0", optional = true } + +[dev-dependencies] +serde_json = "1.0" \ No newline at end of file diff --git a/string/src/lib.rs b/string/src/lib.rs index 2b600bde..7695c6fc 100644 --- a/string/src/lib.rs +++ b/string/src/lib.rs @@ -1,10 +1,11 @@ -//! A utl-8 encoded read-only string with Bytes as a storage. +//! A UTF-8 encoded read-only string using Bytes as storage. + use std::convert::TryFrom; use std::{borrow, fmt, hash, ops, str}; use bytes::Bytes; -/// A utf-8 encoded string with [`Bytes`] as a storage. +/// A UTF-8 encoded string with [`Bytes`] as a storage. /// /// [`Bytes`]: https://docs.rs/bytes/0.5.3/bytes/struct.Bytes.html #[derive(Clone, Eq, Ord, PartialOrd, Default)] @@ -159,6 +160,34 @@ impl fmt::Display for ByteString { } } +#[cfg(feature = "serde")] +mod serde { + use serde::de::{Deserialize, Deserializer}; + use serde::ser::{Serialize, Serializer}; + + use super::ByteString; + + impl Serialize for ByteString { + #[inline] + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str(self.as_ref()) + } + } + + impl<'de> Deserialize<'de> for ByteString { + #[inline] + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + String::deserialize(deserializer).map(ByteString::from) + } + } +} + #[cfg(test)] mod test { use super::*; @@ -222,4 +251,18 @@ mod test { fn test_try_from_bytesmut() { let _ = ByteString::try_from(bytes::BytesMut::from(&b"nice bytes"[..])).unwrap(); } + + #[cfg(feature = "serde")] + #[test] + fn test_serialize() { + let s: ByteString = serde_json::from_str(r#""nice bytes""#).unwrap(); + assert_eq!(s, "nice bytes"); + } + + #[cfg(feature = "serde")] + #[test] + fn test_deserialize() { + let s = serde_json::to_string(&ByteString::from_static("nice bytes")).unwrap(); + assert_eq!(s, r#""nice bytes""#); + } }