Skip to content

Commit

Permalink
Rename Error and HttpError, and move them to root
Browse files Browse the repository at this point in the history
Even clippy now suggests not to use `Error` name because it is becoming
increasingly conflicting with other libs.  Renamed things to `PmtError`
and `PmtHttpError`.  This will probably have merge conflicts with the
other PRs - so just +1 and i will fix it after merge.
  • Loading branch information
nyurik committed Nov 8, 2023
1 parent c7dc1c4 commit 6dc8a57
Show file tree
Hide file tree
Showing 7 changed files with 59 additions and 51 deletions.
37 changes: 20 additions & 17 deletions src/async_reader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use reqwest::{Client, IntoUrl};
use tokio::io::AsyncReadExt;

use crate::directory::{Directory, Entry};
use crate::error::Error;
use crate::error::PmtError;
use crate::header::{HEADER_SIZE, MAX_INITIAL_BYTES};
#[cfg(feature = "http-async")]
use crate::http::HttpBackend;
Expand All @@ -29,7 +29,7 @@ impl<B: AsyncBackend + Sync + Send> AsyncPmTilesReader<B> {
/// Creates a new reader from a specified source and validates the provided PMTiles archive is valid.
///
/// Note: Prefer using new_with_* methods.
pub async fn try_from_source(backend: B) -> Result<Self, Error> {
pub async fn try_from_source(backend: B) -> Result<Self, PmtError> {
let mut initial_bytes = backend.read_initial_bytes().await?;

let header_bytes = initial_bytes.split_to(HEADER_SIZE);
Expand Down Expand Up @@ -75,7 +75,7 @@ impl<B: AsyncBackend + Sync + Send> AsyncPmTilesReader<B> {
///
/// Note: by spec, this should be valid JSON. This method currently returns a [String].
/// This may change in the future.
pub async fn get_metadata(&self) -> Result<String, Error> {
pub async fn get_metadata(&self) -> Result<String, PmtError> {
let metadata = self
.backend
.read_exact(
Expand All @@ -91,13 +91,16 @@ impl<B: AsyncBackend + Sync + Send> AsyncPmTilesReader<B> {
}

#[cfg(feature = "tilejson")]
pub async fn parse_tilejson(&self, sources: Vec<String>) -> Result<tilejson::TileJSON, Error> {
pub async fn parse_tilejson(
&self,
sources: Vec<String>,
) -> Result<tilejson::TileJSON, PmtError> {
use serde_json::Value;

let meta = self.get_metadata().await?;
let meta: Value = serde_json::from_str(&meta).map_err(|_| Error::InvalidMetadata)?;
let meta: Value = serde_json::from_str(&meta).map_err(|_| PmtError::InvalidMetadata)?;
let Value::Object(meta) = meta else {
return Err(Error::InvalidMetadata);
return Err(PmtError::InvalidMetadata);
};

let mut tj = self.header.get_tilejson(sources);
Expand All @@ -123,7 +126,7 @@ impl<B: AsyncBackend + Sync + Send> AsyncPmTilesReader<B> {
if let Ok(v) = serde_json::from_value::<Vec<tilejson::VectorLayer>>(value) {
tj.vector_layers = Some(v);
} else {
return Err(Error::InvalidMetadata);
return Err(PmtError::InvalidMetadata);
}
} else {
tj.other.insert(key, value);
Expand Down Expand Up @@ -167,7 +170,7 @@ impl<B: AsyncBackend + Sync + Send> AsyncPmTilesReader<B> {
}
}

async fn read_directory(&self, offset: usize, length: usize) -> Result<Directory, Error> {
async fn read_directory(&self, offset: usize, length: usize) -> Result<Directory, PmtError> {
Self::read_directory_with_backend(
&self.backend,
self.header.internal_compression,
Expand All @@ -180,7 +183,7 @@ impl<B: AsyncBackend + Sync + Send> AsyncPmTilesReader<B> {
async fn read_compressed_directory(
compression: Compression,
bytes: Bytes,
) -> Result<Directory, Error> {
) -> Result<Directory, PmtError> {
let decompressed_bytes = Self::decompress(compression, bytes).await?;

Directory::try_from(decompressed_bytes)
Expand All @@ -191,13 +194,13 @@ impl<B: AsyncBackend + Sync + Send> AsyncPmTilesReader<B> {
compression: Compression,
offset: usize,
length: usize,
) -> Result<Directory, Error> {
) -> Result<Directory, PmtError> {
let directory_bytes = backend.read_exact(offset, length).await?;

Self::read_compressed_directory(compression, directory_bytes).await
}

async fn decompress(compression: Compression, bytes: Bytes) -> Result<Bytes, Error> {
async fn decompress(compression: Compression, bytes: Bytes) -> Result<Bytes, PmtError> {
let mut decompressed_bytes = Vec::with_capacity(bytes.len() * 2);
match compression {
Compression::Gzip => {
Expand All @@ -217,7 +220,7 @@ impl AsyncPmTilesReader<HttpBackend> {
/// Creates a new PMTiles reader from a URL using the Reqwest backend.
///
/// Fails if [url] does not exist or is an invalid archive. (Note: HTTP requests are made to validate it.)
pub async fn new_with_url<U: IntoUrl>(client: Client, url: U) -> Result<Self, Error> {
pub async fn new_with_url<U: IntoUrl>(client: Client, url: U) -> Result<Self, PmtError> {
let backend = HttpBackend::try_from(client, url)?;

Self::try_from_source(backend).await
Expand All @@ -229,7 +232,7 @@ impl AsyncPmTilesReader<MmapBackend> {
/// Creates a new PMTiles reader from a file path using the async mmap backend.
///
/// Fails if [p] does not exist or is an invalid archive.
pub async fn new_with_path<P: AsRef<Path>>(p: P) -> Result<Self, Error> {
pub async fn new_with_path<P: AsRef<Path>>(p: P) -> Result<Self, PmtError> {
let backend = MmapBackend::try_from(p).await?;

Self::try_from_source(backend).await
Expand All @@ -239,16 +242,16 @@ impl AsyncPmTilesReader<MmapBackend> {
#[async_trait]
pub trait AsyncBackend {
/// Reads exactly `length` bytes starting at `offset`
async fn read_exact(&self, offset: usize, length: usize) -> Result<Bytes, Error>;
async fn read_exact(&self, offset: usize, length: usize) -> Result<Bytes, PmtError>;

/// Reads up to `length` bytes starting at `offset`.
async fn read(&self, offset: usize, length: usize) -> Result<Bytes, Error>;
async fn read(&self, offset: usize, length: usize) -> Result<Bytes, PmtError>;

/// Read the first 127 and up to 16,384 bytes to ensure we can initialize the header and root directory.
async fn read_initial_bytes(&self) -> Result<Bytes, Error> {
async fn read_initial_bytes(&self) -> Result<Bytes, PmtError> {
let bytes = self.read(0, MAX_INITIAL_BYTES).await?;
if bytes.len() < HEADER_SIZE {
return Err(Error::InvalidHeader);
return Err(PmtError::InvalidHeader);
}

Ok(bytes)
Expand Down
8 changes: 4 additions & 4 deletions src/directory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::fmt::{Debug, Formatter};
use bytes::{Buf, Bytes};
use varint_rs::VarintReader;

use crate::error::Error;
use crate::error::PmtError;

pub(crate) struct Directory {
entries: Vec<Entry>,
Expand Down Expand Up @@ -38,9 +38,9 @@ impl Directory {
}

impl TryFrom<Bytes> for Directory {
type Error = Error;
type Error = PmtError;

fn try_from(buffer: Bytes) -> Result<Self, Error> {
fn try_from(buffer: Bytes) -> Result<Self, PmtError> {
let mut buffer = buffer.reader();
let n_entries = buffer.read_usize_varint()?;

Expand Down Expand Up @@ -68,7 +68,7 @@ impl TryFrom<Bytes> for Directory {
for entry in entries.iter_mut() {
let offset = buffer.read_u64_varint()?;
entry.offset = if offset == 0 {
let e = last_entry.ok_or(Error::InvalidEntry)?;
let e = last_entry.ok_or(PmtError::InvalidEntry)?;
e.offset + e.length as u64
} else {
offset - 1
Expand Down
10 changes: 5 additions & 5 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::string::FromUtf8Error;
use thiserror::Error;

#[derive(Debug, Error)]
pub enum Error {
pub enum PmtError {
#[error("Invalid magic number")]
InvalidMagicNumber,
#[error("Invalid PMTiles version")]
Expand All @@ -27,12 +27,12 @@ pub enum Error {
UnableToOpenMmapFile,
#[cfg(feature = "http-async")]
#[error("{0}")]
Http(#[from] HttpError),
Http(#[from] PmtHttpError),
}

#[cfg(feature = "http-async")]
#[derive(Debug, Error)]
pub enum HttpError {
pub enum PmtHttpError {
#[error("Unexpected number of bytes returned [expected: {0}, received: {1}].")]
UnexpectedNumberOfBytesReturned(usize, usize),
#[error("Range requests unsupported")]
Expand All @@ -47,8 +47,8 @@ pub enum HttpError {

// This is required because thiserror #[from] does not support two-level conversion.
#[cfg(feature = "http-async")]
impl From<reqwest::Error> for Error {
impl From<reqwest::Error> for PmtError {
fn from(e: reqwest::Error) -> Self {
Self::Http(HttpError::Http(e))
Self::Http(PmtHttpError::Http(e))
}
}
18 changes: 9 additions & 9 deletions src/header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::panic::catch_unwind;

use bytes::{Buf, Bytes};

use crate::error::Error;
use crate::error::PmtError;

#[cfg(any(feature = "http-async", feature = "mmap-async-tokio"))]
pub(crate) const MAX_INITIAL_BYTES: usize = 16_384;
Expand Down Expand Up @@ -59,7 +59,7 @@ impl Compression {
}

impl TryInto<Compression> for u8 {
type Error = Error;
type Error = PmtError;

fn try_into(self) -> Result<Compression, Self::Error> {
match self {
Expand All @@ -68,7 +68,7 @@ impl TryInto<Compression> for u8 {
2 => Ok(Compression::Gzip),
3 => Ok(Compression::Brotli),
4 => Ok(Compression::Zstd),
_ => Err(Error::InvalidCompression),
_ => Err(PmtError::InvalidCompression),
}
}
}
Expand Down Expand Up @@ -117,7 +117,7 @@ impl TileType {
}

impl TryInto<TileType> for u8 {
type Error = Error;
type Error = PmtError;

fn try_into(self) -> Result<TileType, Self::Error> {
match self {
Expand All @@ -126,7 +126,7 @@ impl TryInto<TileType> for u8 {
2 => Ok(TileType::Png),
3 => Ok(TileType::Jpeg),
4 => Ok(TileType::Webp),
_ => Err(Error::InvalidTileType),
_ => Err(PmtError::InvalidTileType),
}
}
}
Expand All @@ -139,15 +139,15 @@ impl Header {
buf.get_i32_le() as f32 / 10_000_000.
}

pub fn try_from_bytes(mut bytes: Bytes) -> Result<Self, Error> {
pub fn try_from_bytes(mut bytes: Bytes) -> Result<Self, PmtError> {
let magic_bytes = bytes.split_to(V3_MAGIC.len());

// Assert magic
if magic_bytes != V3_MAGIC {
return Err(if magic_bytes.starts_with(V2_MAGIC.as_bytes()) {
Error::UnsupportedPmTilesVersion
PmtError::UnsupportedPmTilesVersion
} else {
Error::InvalidMagicNumber
PmtError::InvalidMagicNumber
});
}

Expand Down Expand Up @@ -181,7 +181,7 @@ impl Header {
center_latitude: Self::read_coordinate_part(&mut bytes),
})
})
.map_err(|_| Error::InvalidHeader)?
.map_err(|_| PmtError::InvalidHeader)?
}
}

Expand Down
16 changes: 8 additions & 8 deletions src/http.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ use reqwest::header::{HeaderValue, RANGE};
use reqwest::{Client, IntoUrl, Method, Request, StatusCode, Url};

use crate::async_reader::AsyncBackend;
use crate::error::{Error, HttpError};
use crate::error::{PmtError, PmtHttpError};

pub struct HttpBackend {
client: Client,
pmtiles_url: Url,
}

impl HttpBackend {
pub fn try_from<U: IntoUrl>(client: Client, url: U) -> Result<Self, Error> {
pub fn try_from<U: IntoUrl>(client: Client, url: U) -> Result<Self, PmtError> {
Ok(HttpBackend {
client,
pmtiles_url: url.into_url()?,
Expand All @@ -22,32 +22,32 @@ impl HttpBackend {

#[async_trait]
impl AsyncBackend for HttpBackend {
async fn read_exact(&self, offset: usize, length: usize) -> Result<Bytes, Error> {
async fn read_exact(&self, offset: usize, length: usize) -> Result<Bytes, PmtError> {
let data = self.read(offset, length).await?;

if data.len() == length {
Ok(data)
} else {
Err(HttpError::UnexpectedNumberOfBytesReturned(length, data.len()).into())
Err(PmtHttpError::UnexpectedNumberOfBytesReturned(length, data.len()).into())
}
}

async fn read(&self, offset: usize, length: usize) -> Result<Bytes, Error> {
async fn read(&self, offset: usize, length: usize) -> Result<Bytes, PmtError> {
let end = offset + length - 1;
let range = format!("bytes={offset}-{end}");
let range = HeaderValue::try_from(range).map_err(HttpError::from)?;
let range = HeaderValue::try_from(range).map_err(PmtHttpError::from)?;

let mut req = Request::new(Method::GET, self.pmtiles_url.clone());
req.headers_mut().insert(RANGE, range);

let response = self.client.execute(req).await?.error_for_status()?;
if response.status() != StatusCode::PARTIAL_CONTENT {
return Err(HttpError::RangeRequestsUnsupported.into());
return Err(PmtHttpError::RangeRequestsUnsupported.into());
}

let response_bytes = response.bytes().await?;
if response_bytes.len() > length {
Err(HttpError::ResponseBodyTooLong(response_bytes.len(), length).into())
Err(PmtHttpError::ResponseBodyTooLong(response_bytes.len(), length).into())
} else {
Ok(response_bytes)
}
Expand Down
7 changes: 6 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,12 @@
pub use crate::header::{Compression, Header, TileType};

mod directory;
pub mod error;

mod error;
pub use error::PmtError;
#[cfg(feature = "http-async")]
pub use error::PmtHttpError;

mod header;

#[cfg(feature = "http-async")]
Expand Down
14 changes: 7 additions & 7 deletions src/mmap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,41 +6,41 @@ use bytes::{Buf, Bytes};
use fmmap::tokio::{AsyncMmapFile, AsyncMmapFileExt as _, AsyncOptions};

use crate::async_reader::AsyncBackend;
use crate::error::Error;
use crate::error::PmtError;

pub struct MmapBackend {
file: AsyncMmapFile,
}

impl MmapBackend {
pub async fn try_from<P: AsRef<Path>>(p: P) -> Result<Self, Error> {
pub async fn try_from<P: AsRef<Path>>(p: P) -> Result<Self, PmtError> {
Ok(Self {
file: AsyncMmapFile::open_with_options(p, AsyncOptions::new().read(true))
.await
.map_err(|_| Error::UnableToOpenMmapFile)?,
.map_err(|_| PmtError::UnableToOpenMmapFile)?,
})
}
}

impl From<fmmap::error::Error> for Error {
impl From<fmmap::error::Error> for PmtError {
fn from(_: fmmap::error::Error) -> Self {
Self::Reading(io::Error::from(io::ErrorKind::UnexpectedEof))
}
}

#[async_trait]
impl AsyncBackend for MmapBackend {
async fn read_exact(&self, offset: usize, length: usize) -> Result<Bytes, Error> {
async fn read_exact(&self, offset: usize, length: usize) -> Result<Bytes, PmtError> {
if self.file.len() >= offset + length {
Ok(self.file.reader(offset)?.copy_to_bytes(length))
} else {
Err(Error::Reading(io::Error::from(
Err(PmtError::Reading(io::Error::from(
io::ErrorKind::UnexpectedEof,
)))
}
}

async fn read(&self, offset: usize, length: usize) -> Result<Bytes, Error> {
async fn read(&self, offset: usize, length: usize) -> Result<Bytes, PmtError> {
let reader = self.file.reader(offset)?;

let read_length = length.min(reader.len());
Expand Down

0 comments on commit 6dc8a57

Please sign in to comment.