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> {
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;
587587pub 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]
591600pub 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 {
901900as_ref_impl ! ( Arc <dyn ObjectStore >) ;
902901as_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.
0 commit comments