Skip to content

Commit 0f861bc

Browse files
committed
refactor: introduce ObjectStoreExt trait
See #385.
1 parent 40d30c6 commit 0f861bc

File tree

12 files changed

+64
-41
lines changed

12 files changed

+64
-41
lines changed

src/aws/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -499,6 +499,7 @@ mod tests {
499499
use crate::integration::*;
500500
use crate::tests::*;
501501
use crate::ClientOptions;
502+
use crate::ObjectStoreExt;
502503
use base64::prelude::BASE64_STANDARD;
503504
use base64::Engine;
504505
use http::HeaderMap;

src/azure/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,7 @@ mod tests {
309309
use super::*;
310310
use crate::integration::*;
311311
use crate::tests::*;
312+
use crate::ObjectStoreExt;
312313
use bytes::Bytes;
313314

314315
#[tokio::test]

src/buffered.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -210,12 +210,12 @@ impl AsyncBufRead for BufReader {
210210

211211
/// An async buffered writer compatible with the tokio IO traits
212212
///
213-
/// This writer adaptively uses [`ObjectStore::put`] or
213+
/// This writer adaptively uses [`ObjectStore::put_opts`] or
214214
/// [`ObjectStore::put_multipart`] depending on the amount of data that has
215215
/// been written.
216216
///
217217
/// Up to `capacity` bytes will be buffered in memory, and flushed on shutdown
218-
/// using [`ObjectStore::put`]. If `capacity` is exceeded, data will instead be
218+
/// using [`ObjectStore::put_opts`]. If `capacity` is exceeded, data will instead be
219219
/// streamed using [`ObjectStore::put_multipart`]
220220
pub struct BufWriter {
221221
capacity: usize,
@@ -242,7 +242,7 @@ enum BufWriterState {
242242
Prepare(BoxFuture<'static, crate::Result<WriteMultipart>>),
243243
/// Write to a multipart upload
244244
Write(Option<WriteMultipart>),
245-
/// [`ObjectStore::put`]
245+
/// [`ObjectStore::put_opts`]
246246
Flush(BoxFuture<'static, crate::Result<()>>),
247247
}
248248

@@ -489,7 +489,7 @@ mod tests {
489489
use super::*;
490490
use crate::memory::InMemory;
491491
use crate::path::Path;
492-
use crate::{Attribute, GetOptions};
492+
use crate::{Attribute, GetOptions, ObjectStoreExt};
493493
use itertools::Itertools;
494494
use tokio::io::{AsyncBufReadExt, AsyncReadExt, AsyncSeekExt, AsyncWriteExt};
495495

src/chunked.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@ mod tests {
185185
use crate::local::LocalFileSystem;
186186
use crate::memory::InMemory;
187187
use crate::path::Path;
188+
use crate::ObjectStoreExt;
188189

189190
use super::*;
190191

src/gcp/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,7 @@ mod test {
287287

288288
use crate::integration::*;
289289
use crate::tests::*;
290+
use crate::ObjectStoreExt;
290291

291292
use super::*;
292293

src/integration.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ use crate::multipart::MultipartStore;
2929
use crate::path::Path;
3030
use crate::{
3131
Attribute, Attributes, DynObjectStore, Error, GetOptions, GetRange, MultipartUpload,
32-
ObjectStore, PutMode, PutPayload, UpdateVersion, WriteMultipart,
32+
ObjectStore, ObjectStoreExt, PutMode, PutPayload, UpdateVersion, WriteMultipart,
3333
};
3434
use bytes::Bytes;
3535
use futures::stream::FuturesUnordered;

src/lib.rs

Lines changed: 50 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -252,11 +252,11 @@
252252
//!
253253
//! # Put Object
254254
//!
255-
//! Use the [`ObjectStore::put`] method to atomically write data.
255+
//! Use the [`ObjectStoreExt::put`] method to atomically write data.
256256
//!
257257
//! ```
258258
//! # use object_store::local::LocalFileSystem;
259-
//! # use object_store::{ObjectStore, PutPayload};
259+
//! # use object_store::{ObjectStore, ObjectStoreExt, PutPayload};
260260
//! # use std::sync::Arc;
261261
//! # use object_store::path::Path;
262262
//! # fn get_object_store() -> Arc<dyn ObjectStore> {
@@ -338,7 +338,7 @@
338338
//!
339339
//! ```
340340
//! # use object_store::local::LocalFileSystem;
341-
//! # use object_store::{ObjectStore, PutPayloadMut};
341+
//! # use object_store::{ObjectStore, ObjectStoreExt, PutPayloadMut};
342342
//! # use std::sync::Arc;
343343
//! # use bytes::Bytes;
344344
//! # use tokio::io::AsyncWriteExt;
@@ -587,19 +587,22 @@ pub type DynObjectStore = dyn ObjectStore;
587587
pub type MultipartId = String;
588588

589589
/// Universal API to multiple object store services.
590+
///
591+
/// For more convience methods, check [`ObjectStoreExt`].
592+
///
593+
/// # Contract
594+
/// This trait is meant as a contract between object store implementations
595+
/// (e.g. providers, wrappers) and the `object_store` crate itself.
596+
///
597+
/// The [`ObjectStoreExt`] acts as an API/contract between `object_store`
598+
/// and the store users.
590599
#[async_trait]
591600
pub trait ObjectStore: std::fmt::Display + Send + Sync + Debug + 'static {
592-
/// Save the provided bytes to the specified location
601+
/// Save the provided `payload` to `location` with the given options
593602
///
594603
/// The operation is guaranteed to be atomic, it will either successfully
595604
/// write the entirety of `payload` to `location`, or fail. No clients
596605
/// should be able to observe a partially written object
597-
async fn put(&self, location: &Path, payload: PutPayload) -> Result<PutResult> {
598-
self.put_opts(location, payload, PutOptions::default())
599-
.await
600-
}
601-
602-
/// Save the provided `payload` to `location` with the given options
603606
async fn put_opts(
604607
&self,
605608
location: &Path,
@@ -609,7 +612,7 @@ pub trait ObjectStore: std::fmt::Display + Send + Sync + Debug + 'static {
609612

610613
/// Perform a multipart upload
611614
///
612-
/// Client should prefer [`ObjectStore::put`] for small payloads, as streaming uploads
615+
/// Client should prefer [`ObjectStoreExt::put`] for small payloads, as streaming uploads
613616
/// typically require multiple separate requests. See [`MultipartUpload`] for more information
614617
///
615618
/// For more advanced multipart uploads see [`MultipartStore`](multipart::MultipartStore)
@@ -620,7 +623,7 @@ pub trait ObjectStore: std::fmt::Display + Send + Sync + Debug + 'static {
620623

621624
/// Perform a multipart upload with options
622625
///
623-
/// Client should prefer [`ObjectStore::put`] for small payloads, as streaming uploads
626+
/// Client should prefer [`ObjectStore::put_opts`] for small payloads, as streaming uploads
624627
/// typically require multiple separate requests. See [`MultipartUpload`] for more information
625628
///
626629
/// For more advanced multipart uploads see [`MultipartStore`](multipart::MultipartStore)
@@ -696,7 +699,7 @@ pub trait ObjectStore: std::fmt::Display + Send + Sync + Debug + 'static {
696699
/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
697700
/// # let root = tempfile::TempDir::new().unwrap();
698701
/// # let store = LocalFileSystem::new_with_prefix(root.path()).unwrap();
699-
/// # use object_store::{ObjectStore, ObjectMeta};
702+
/// # use object_store::{ObjectStore, ObjectStoreExt, ObjectMeta};
700703
/// # use object_store::path::Path;
701704
/// # use futures::{StreamExt, TryStreamExt};
702705
/// #
@@ -803,10 +806,6 @@ macro_rules! as_ref_impl {
803806
($type:ty) => {
804807
#[async_trait]
805808
impl ObjectStore for $type {
806-
async fn put(&self, location: &Path, payload: PutPayload) -> Result<PutResult> {
807-
self.as_ref().put(location, payload).await
808-
}
809-
810809
async fn put_opts(
811810
&self,
812811
location: &Path,
@@ -901,6 +900,40 @@ macro_rules! as_ref_impl {
901900
as_ref_impl!(Arc<dyn ObjectStore>);
902901
as_ref_impl!(Box<dyn ObjectStore>);
903902

903+
/// Helper module to [seal traits](https://predr.ag/blog/definitive-guide-to-sealed-traits-in-rust/).
904+
mod private {
905+
pub trait Sealed {}
906+
907+
impl<T> Sealed for T where T: super::ObjectStore + ?Sized {}
908+
}
909+
910+
/// Extension trait for [`ObjectStore`] with convinience functions.
911+
///
912+
/// See "contract" section within the [`ObjectStore`] documentation for more reasoning.
913+
///
914+
/// # Implementation
915+
/// You MUST NOT implement this trait yourself. It is automatically implemented for all [`ObjectStore`] implementations.
916+
#[async_trait]
917+
pub trait ObjectStoreExt: private::Sealed {
918+
/// Save the provided bytes to the specified location
919+
///
920+
/// The operation is guaranteed to be atomic, it will either successfully
921+
/// write the entirety of `payload` to `location`, or fail. No clients
922+
/// should be able to observe a partially written object
923+
async fn put(&self, location: &Path, payload: PutPayload) -> Result<PutResult>;
924+
}
925+
926+
#[async_trait]
927+
impl<T> ObjectStoreExt for T
928+
where
929+
T: ObjectStore + private::Sealed + ?Sized,
930+
{
931+
async fn put(&self, location: &Path, payload: PutPayload) -> Result<PutResult> {
932+
self.put_opts(location, payload, PutOptions::default())
933+
.await
934+
}
935+
}
936+
904937
/// Result of a list call that includes objects, prefixes (directories) and a
905938
/// token for the next set of results. Individual result sets may be limited to
906939
/// 1,000 objects based on the underlying object storage's limitations.

src/limit.rs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -71,11 +71,6 @@ impl<T: ObjectStore> std::fmt::Display for LimitStore<T> {
7171

7272
#[async_trait]
7373
impl<T: ObjectStore> ObjectStore for LimitStore<T> {
74-
async fn put(&self, location: &Path, payload: PutPayload) -> Result<PutResult> {
75-
let _permit = self.semaphore.acquire().await.unwrap();
76-
self.inner.put(location, payload).await
77-
}
78-
7974
async fn put_opts(
8075
&self,
8176
location: &Path,

src/local.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1090,7 +1090,7 @@ mod tests {
10901090
#[cfg(target_family = "unix")]
10911091
use tempfile::NamedTempFile;
10921092

1093-
use crate::integration::*;
1093+
use crate::{integration::*, ObjectStoreExt};
10941094

10951095
use super::*;
10961096

src/memory.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -536,7 +536,7 @@ impl MultipartUpload for InMemoryUpload {
536536

537537
#[cfg(test)]
538538
mod tests {
539-
use crate::integration::*;
539+
use crate::{integration::*, ObjectStoreExt};
540540

541541
use super::*;
542542

0 commit comments

Comments
 (0)