From 64f39ec915de9790527e738c7e6fd358f85e3c0f Mon Sep 17 00:00:00 2001 From: Yuri Astrakhan Date: Thu, 11 Apr 2024 02:04:51 -0400 Subject: [PATCH] Remove async_trait dependency, MSRV CI (#37) Requires Rust v1.75 - old enough to release now Also fixes a few pedantic clippy things and CI improvements --- .github/workflows/test.yml | 26 +++++++++++++++++++++++++- Cargo.toml | 5 ++--- src/async_reader.rs | 15 +++++++++------ src/backend_http.rs | 5 +---- src/backend_mmap.rs | 2 -- src/backend_s3.rs | 2 -- src/cache.rs | 19 +++++++++++-------- 7 files changed, 48 insertions(+), 26 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 76172f4..1981e43 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -15,7 +15,9 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout sources - uses: actions/checkout@v3 + uses: actions/checkout@v4 + - uses: Swatinem/rust-cache@v2 + if: github.event_name != 'release' && github.event_name != 'workflow_dispatch' - run: | rustc --version @@ -34,3 +36,25 @@ jobs: - run: cargo test - name: Check semver uses: obi1kenobi/cargo-semver-checks-action@v2 + + msrv: + name: Test MSRV + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: Swatinem/rust-cache@v2 + if: github.event_name != 'release' && github.event_name != 'workflow_dispatch' + - name: Read crate metadata + id: metadata + run: echo "rust-version=$(sed -ne 's/rust-version *= *\"\(.*\)\"/\1/p' Cargo.toml)" >> $GITHUB_OUTPUT + - name: Install Rust + uses: dtolnay/rust-toolchain@stable + with: + toolchain: ${{ steps.metadata.outputs.rust-version }} + - run: cargo test --all-targets --all-features + - run: cargo test --features http-async + - run: cargo test --features mmap-async-tokio + - run: cargo test --features tilejson + - run: cargo test --features s3-async-native + - run: cargo test --features s3-async-rustls + - run: cargo test diff --git a/Cargo.toml b/Cargo.toml index 4aa0422..22beac4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,13 +1,13 @@ [package] name = "pmtiles" -version = "0.8.0" +version = "0.9.0" edition = "2021" authors = ["Luke Seelenbinder "] license = "MIT OR Apache-2.0" description = "Implementation of the PMTiles v3 spec with multiple sync and async backends." repository = "https://github.com/stadiamaps/pmtiles-rs" keywords = ["pmtiles", "gis", "geo"] -rust-version = "1.68.2" +rust-version = "1.75.0" categories = ["science::geo"] [features] @@ -35,7 +35,6 @@ __async-s3-rustls = ["rust-s3?/tokio-rustls-tls"] # TODO: determine how we want to handle compression in async & sync environments async-compression = { version = "0.4", features = ["gzip", "zstd", "brotli"] } async-recursion = "1" -async-trait = "0.1" bytes = "1" fmmap = { version = "0.3", default-features = false, optional = true } hilbert_2d = "1" diff --git a/src/async_reader.rs b/src/async_reader.rs index 115db30..170a71d 100644 --- a/src/async_reader.rs +++ b/src/async_reader.rs @@ -2,8 +2,9 @@ // so any file larger than 4GB, or an untrusted file with bad data may crash. #![allow(clippy::cast_possible_truncation)] +use std::future::Future; + use async_recursion::async_recursion; -use async_trait::async_trait; use bytes::Bytes; #[cfg(feature = "__async")] use tokio::io::AsyncReadExt; @@ -213,23 +214,25 @@ impl AsyncPmTile } } -#[async_trait] pub trait AsyncBackend { /// Reads exactly `length` bytes starting at `offset` - async fn read_exact(&self, offset: usize, length: usize) -> PmtResult; + fn read_exact( + &self, + offset: usize, + length: usize, + ) -> impl Future> + Send; /// Reads up to `length` bytes starting at `offset`. - async fn read(&self, offset: usize, length: usize) -> PmtResult; + fn read(&self, offset: usize, length: usize) -> impl Future> + Send; } #[cfg(test)] #[cfg(feature = "mmap-async-tokio")] mod tests { + use super::AsyncPmTilesReader; use crate::tests::{RASTER_FILE, VECTOR_FILE}; use crate::MmapBackend; - use super::AsyncPmTilesReader; - #[tokio::test] async fn open_sanity_check() { let backend = MmapBackend::try_from(RASTER_FILE).await.unwrap(); diff --git a/src/backend_http.rs b/src/backend_http.rs index 56866ab..14180de 100644 --- a/src/backend_http.rs +++ b/src/backend_http.rs @@ -1,4 +1,3 @@ -use async_trait::async_trait; use bytes::Bytes; use reqwest::header::{HeaderValue, RANGE}; use reqwest::{Client, IntoUrl, Method, Request, StatusCode, Url}; @@ -46,7 +45,6 @@ impl HttpBackend { } } -#[async_trait] impl AsyncBackend for HttpBackend { async fn read_exact(&self, offset: usize, length: usize) -> PmtResult { let data = self.read(offset, length).await?; @@ -86,14 +84,13 @@ impl AsyncBackend for HttpBackend { #[cfg(test)] mod tests { use super::*; - use crate::async_reader::AsyncPmTilesReader; static TEST_URL: &str = "https://protomaps.github.io/PMTiles/protomaps(vector)ODbL_firenze.pmtiles"; #[tokio::test] async fn basic_http_test() { - let client = reqwest::Client::builder().use_rustls_tls().build().unwrap(); + let client = Client::builder().use_rustls_tls().build().unwrap(); let backend = HttpBackend::try_from(client, TEST_URL).unwrap(); AsyncPmTilesReader::try_from_source(backend).await.unwrap(); diff --git a/src/backend_mmap.rs b/src/backend_mmap.rs index deef24a..642bace 100644 --- a/src/backend_mmap.rs +++ b/src/backend_mmap.rs @@ -1,7 +1,6 @@ use std::io; use std::path::Path; -use async_trait::async_trait; use bytes::{Buf, Bytes}; use fmmap::tokio::{AsyncMmapFile, AsyncMmapFileExt as _, AsyncOptions}; @@ -49,7 +48,6 @@ impl From for PmtError { } } -#[async_trait] impl AsyncBackend for MmapBackend { async fn read_exact(&self, offset: usize, length: usize) -> PmtResult { if self.file.len() >= offset + length { diff --git a/src/backend_s3.rs b/src/backend_s3.rs index 32fba59..89902cd 100644 --- a/src/backend_s3.rs +++ b/src/backend_s3.rs @@ -1,4 +1,3 @@ -use async_trait::async_trait; use bytes::Bytes; use s3::Bucket; @@ -43,7 +42,6 @@ impl S3Backend { } } -#[async_trait] impl AsyncBackend for S3Backend { async fn read_exact(&self, offset: usize, length: usize) -> PmtResult { let data = self.read(offset, length).await?; diff --git a/src/cache.rs b/src/cache.rs index bd9a844..da3bb76 100644 --- a/src/cache.rs +++ b/src/cache.rs @@ -1,8 +1,7 @@ use std::collections::HashMap; +use std::future::Future; use std::sync::{Arc, RwLock}; -use async_trait::async_trait; - use crate::directory::{DirEntry, Directory}; pub enum DirCacheResult { @@ -20,20 +19,25 @@ impl From> for DirCacheResult { } } -/// A cache for PMTiles directories. -#[async_trait] +/// A cache for `PMTiles` directories. pub trait DirectoryCache { /// Get a directory from the cache, using the offset as a key. - async fn get_dir_entry(&self, offset: usize, tile_id: u64) -> DirCacheResult; + fn get_dir_entry( + &self, + offset: usize, + tile_id: u64, + ) -> impl Future + Send; /// Insert a directory into the cache, using the offset as a key. /// Note that cache must be internally mutable. - async fn insert_dir(&self, offset: usize, directory: Directory); + fn insert_dir(&self, offset: usize, directory: Directory) -> impl Future + Send; } pub struct NoCache; -#[async_trait] +// TODO: Remove #[allow] after switching to Rust/Clippy v1.78+ in CI +// See https://github.com/rust-lang/rust-clippy/pull/12323 +#[allow(clippy::no_effect_underscore_binding)] impl DirectoryCache for NoCache { #[inline] async fn get_dir_entry(&self, _offset: usize, _tile_id: u64) -> DirCacheResult { @@ -50,7 +54,6 @@ pub struct HashMapCache { pub cache: Arc>>, } -#[async_trait] impl DirectoryCache for HashMapCache { async fn get_dir_entry(&self, offset: usize, tile_id: u64) -> DirCacheResult { if let Some(dir) = self.cache.read().unwrap().get(&offset) {