pub trait ObjectStore:
Send
+ Sync
+ Debug {
Show 16 methods
// Required methods
fn head<'life0, 'life1, 'async_trait>(
&'life0 self,
key: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Option<ObjectMetadata>>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait;
fn get_with_metadata<'life0, 'life1, 'async_trait>(
&'life0 self,
key: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Option<ObjectBody>>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait;
fn get<'life0, 'life1, 'async_trait>(
&'life0 self,
key: &'life1 str,
range: Option<ByteRange>,
) -> Pin<Box<dyn Future<Output = Result<Option<Bytes>>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait;
fn put<'life0, 'life1, 'async_trait>(
&'life0 self,
key: &'life1 str,
bytes: Bytes,
mode: PutMode,
) -> Pin<Box<dyn Future<Output = Result<ObjectMetadata>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait;
fn delete<'life0, 'life1, 'async_trait>(
&'life0 self,
key: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait;
fn list_prefix_stream(
&self,
prefix: &str,
) -> BoxStream<'static, Result<String>>;
// Provided methods
fn head_stored_checksum<'life0, 'life1, 'async_trait>(
&'life0 self,
key: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Option<StoredObjectChecksum>>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait { ... }
fn create_multipart_upload<'life0, 'life1, 'async_trait>(
&'life0 self,
key: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<String>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait { ... }
fn complete_multipart_upload<'life0, 'life1, 'life2, 'life3, 'life4, 'async_trait>(
&'life0 self,
key: &'life1 str,
provider_upload_id: &'life2 str,
parts: &'life3 [MultipartPart],
full_object_checksum: &'life4 StorageChecksum,
) -> Pin<Box<dyn Future<Output = Result<MultipartCompletion>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
'life4: 'async_trait { ... }
fn abort_multipart_upload<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
key: &'life1 str,
provider_upload_id: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait { ... }
fn put_streamed<'life0, 'life1, 'async_trait>(
&'life0 self,
key: &'life1 str,
body: ByteStream,
mode: PutMode,
) -> Pin<Box<dyn Future<Output = Result<u64>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait { ... }
fn list_prefix<'life0, 'life1, 'async_trait>(
&'life0 self,
prefix: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Vec<String>>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait { ... }
fn put_overwrite<'life0, 'life1, 'async_trait>(
&'life0 self,
key: &'life1 str,
bytes: Bytes,
) -> Pin<Box<dyn Future<Output = Result<ObjectMetadata>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait { ... }
fn put_if_absent<'life0, 'life1, 'async_trait>(
&'life0 self,
key: &'life1 str,
bytes: Bytes,
) -> Pin<Box<dyn Future<Output = Result<ObjectMetadata>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait { ... }
fn put_immutable_verified<'life0, 'life1, 'async_trait>(
&'life0 self,
key: &'life1 str,
bytes: Bytes,
) -> Pin<Box<dyn Future<Output = Result<(), ImmutableWriteError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait { ... }
fn compare_and_swap<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
key: &'life1 str,
expected_etag: &'life2 str,
bytes: Bytes,
) -> Pin<Box<dyn Future<Output = Result<ObjectMetadata>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait { ... }
}Expand description
Defines the provider-independent durability and consistency boundary LoonFS relies on.
Implementations must satisfy the required guarantees.
Required Methods§
Sourcefn head<'life0, 'life1, 'async_trait>(
&'life0 self,
key: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Option<ObjectMetadata>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn head<'life0, 'life1, 'async_trait>(
&'life0 self,
key: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Option<ObjectMetadata>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Reads metadata for one key, returning None when the object is absent.
The returned compare token belongs to this exact observation. Invalid
keys and provider failures are returned as ObjectStoreError.
Sourcefn get_with_metadata<'life0, 'life1, 'async_trait>(
&'life0 self,
key: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Option<ObjectBody>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn get_with_metadata<'life0, 'life1, 'async_trait>(
&'life0 self,
key: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Option<ObjectBody>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Reads complete bytes and identity metadata from one self-consistent observation.
Returns None when the object is absent; invalid keys and provider
failures are returned as ObjectStoreError.
Sourcefn get<'life0, 'life1, 'async_trait>(
&'life0 self,
key: &'life1 str,
range: Option<ByteRange>,
) -> Pin<Box<dyn Future<Output = Result<Option<Bytes>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn get<'life0, 'life1, 'async_trait>(
&'life0 self,
key: &'life1 str,
range: Option<ByteRange>,
) -> Pin<Box<dyn Future<Output = Result<Option<Bytes>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Reads a full object or one half-open byte range, returning None when absent.
A range ending beyond the object is truncated; a descending range or
start beyond the object returns ObjectStoreError::InvalidRange.
Sourcefn put<'life0, 'life1, 'async_trait>(
&'life0 self,
key: &'life1 str,
bytes: Bytes,
mode: PutMode,
) -> Pin<Box<dyn Future<Output = Result<ObjectMetadata>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn put<'life0, 'life1, 'async_trait>(
&'life0 self,
key: &'life1 str,
bytes: Bytes,
mode: PutMode,
) -> Pin<Box<dyn Future<Output = Result<ObjectMetadata>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Writes bytes under the requested overwrite or provider-enforced precondition.
Successful completion is immediately authoritative. Invalid keys, failed conditions, permission failures, and ambiguous transport failures are returned.
Sourcefn delete<'life0, 'life1, 'async_trait>(
&'life0 self,
key: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn delete<'life0, 'life1, 'async_trait>(
&'life0 self,
key: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Deletes a key idempotently and makes its absence immediately authoritative.
Missing objects succeed; invalid keys, permission failures, and ambiguous transport failures are returned.
Provided Methods§
Sourcefn head_stored_checksum<'life0, 'life1, 'async_trait>(
&'life0 self,
key: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Option<StoredObjectChecksum>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn head_stored_checksum<'life0, 'life1, 'async_trait>(
&'life0 self,
key: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Option<StoredObjectChecksum>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Reads size and the stored full-object checksum for one key, returning
None when the object is absent.
This is exactly one metadata request. S3-family stores issue
HeadObject with checksum mode enabled; GetObjectAttributes is
never used anywhere, because Cloudflare R2 answers it with 501 and
code that reaches for it passes its tests against S3 and fails in
production.
Stores that cannot report a stored checksum return
ObjectStoreError::Unsupported. That is the same capability line
as presigned direct uploads: a deployment whose provider cannot show
the checksum back also cannot offer direct_put, because completion
would have nothing to verify against.
Sourcefn create_multipart_upload<'life0, 'life1, 'async_trait>(
&'life0 self,
key: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<String>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn create_multipart_upload<'life0, 'life1, 'async_trait>(
&'life0 self,
key: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<String>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Opens a provider multipart upload targeting key, whose eventual
checksum covers the whole assembled object.
This is the control half of a client-driven multipart upload: the
bytes travel from the client straight to the provider under signed
per-part capabilities, and the store only opens, closes, and abandons
the upload. Stores that cannot express it return
ObjectStoreError::Unsupported.
Sourcefn complete_multipart_upload<'life0, 'life1, 'life2, 'life3, 'life4, 'async_trait>(
&'life0 self,
key: &'life1 str,
provider_upload_id: &'life2 str,
parts: &'life3 [MultipartPart],
full_object_checksum: &'life4 StorageChecksum,
) -> Pin<Box<dyn Future<Output = Result<MultipartCompletion>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
'life4: 'async_trait,
fn complete_multipart_upload<'life0, 'life1, 'life2, 'life3, 'life4, 'async_trait>(
&'life0 self,
key: &'life1 str,
provider_upload_id: &'life2 str,
parts: &'life3 [MultipartPart],
full_object_checksum: &'life4 StorageChecksum,
) -> Pin<Box<dyn Future<Output = Result<MultipartCompletion>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
'life4: 'async_trait,
Asks the provider to assemble parts into the object at key.
full_object_checksum is supplied as a precondition where the
provider honours one. It is not sufficient evidence on its own:
Cloudflare R2 accepts a wrong claim, assembles the object, and
reports the true checksum, so a caller must read the object’s stored
checksum back before believing anything about its bytes.
Sourcefn abort_multipart_upload<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
key: &'life1 str,
provider_upload_id: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn abort_multipart_upload<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
key: &'life1 str,
provider_upload_id: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Abandons a provider multipart upload and the parts it accumulated.
Aborting an upload that already completed is safe on every provider LoonFS supports: it succeeds and leaves the assembled object alone. An upload the provider has never heard of also succeeds, so cleanup can run without first proving what state it is cleaning up.
Sourcefn put_streamed<'life0, 'life1, 'async_trait>(
&'life0 self,
key: &'life1 str,
body: ByteStream,
mode: PutMode,
) -> Pin<Box<dyn Future<Output = Result<u64>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn put_streamed<'life0, 'life1, 'async_trait>(
&'life0 self,
key: &'life1 str,
body: ByteStream,
mode: PutMode,
) -> Pin<Box<dyn Future<Output = Result<u64>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Writes a payload of unknown length without holding it whole, and reports how many bytes were stored.
This is for immutable objects at uniquely-named keys — content blobs. Two properties define it:
- Bounded memory. A store that can write incrementally holds at most one internal buffer at a time, whatever the payload’s length. The default implementation cannot, and says so below.
- The body is consumed before any precondition is evaluated. A caller folding a digest over the stream as it forwards it therefore always ends up with a digest over the complete payload, even when the write is refused — which is what lets it tell “these are the same bytes again” from “these are different bytes”.
mode is honoured exactly while the payload fits inside one
internal part. Beyond that, the write goes through the provider’s
multipart upload, whose completion is an unconditional overwrite, so
a create-only or compare-and-swap request degrades to one there.
That is the same trade Self::put_immutable_verified already makes
at its multipart threshold, and the reason both are for immutable
keys only: on a key whose bytes are fixed by its name, the condition
is a corruption tripwire rather than a concurrency control.
A failed or abandoned write leaves no provider state behind: an implementation that opened a multipart upload aborts it.
The default implementation buffers the whole stream and delegates
to Self::put. It exists so a provider without an incremental
write is honest rather than absent: its memory cost is exactly what
buffering the payload and calling put costs today, and it is
bounded only by whatever bounds the caller puts on the stream.
Sourcefn list_prefix<'life0, 'life1, 'async_trait>(
&'life0 self,
prefix: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Vec<String>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn list_prefix<'life0, 'life1, 'async_trait>(
&'life0 self,
prefix: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Vec<String>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Collects and sorts every key under prefix.
The operation fails if prefix validation or any streamed provider page fails.
Sourcefn put_overwrite<'life0, 'life1, 'async_trait>(
&'life0 self,
key: &'life1 str,
bytes: Bytes,
) -> Pin<Box<dyn Future<Output = Result<ObjectMetadata>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn put_overwrite<'life0, 'life1, 'async_trait>(
&'life0 self,
key: &'life1 str,
bytes: Bytes,
) -> Pin<Box<dyn Future<Output = Result<ObjectMetadata>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Writes bytes unconditionally, replacing any existing object at key.
Invalid keys, permission failures, and ambiguous transport failures are returned.
Sourcefn put_if_absent<'life0, 'life1, 'async_trait>(
&'life0 self,
key: &'life1 str,
bytes: Bytes,
) -> Pin<Box<dyn Future<Output = Result<ObjectMetadata>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn put_if_absent<'life0, 'life1, 'async_trait>(
&'life0 self,
key: &'life1 str,
bytes: Bytes,
) -> Pin<Box<dyn Future<Output = Result<ObjectMetadata>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Creates key only when no object is present.
Existing objects return ObjectStoreError::PreconditionFailed;
invalid keys, permission failures, and transport failures are also returned.
Sourcefn put_immutable_verified<'life0, 'life1, 'async_trait>(
&'life0 self,
key: &'life1 str,
bytes: Bytes,
) -> Pin<Box<dyn Future<Output = Result<(), ImmutableWriteError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn put_immutable_verified<'life0, 'life1, 'async_trait>(
&'life0 self,
key: &'life1 str,
bytes: Bytes,
) -> Pin<Box<dyn Future<Output = Result<(), ImmutableWriteError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Writes bytes under an immutable key and accepts success only when
the key contains exactly those bytes.
Payloads below crate::PROVIDER_MULTIPART_THRESHOLD_BYTES use
create-if-absent; payloads at or above that threshold use the store’s
multipart-capable overwrite path. Transport retries are safe only
because every writer allowed to name this immutable key must supply
identical bytes. Mutable keys must use Self::put and own their
protocol-specific ambiguity resolution.
Sourcefn compare_and_swap<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
key: &'life1 str,
expected_etag: &'life2 str,
bytes: Bytes,
) -> Pin<Box<dyn Future<Output = Result<ObjectMetadata>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn compare_and_swap<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
key: &'life1 str,
expected_etag: &'life2 str,
bytes: Bytes,
) -> Pin<Box<dyn Future<Output = Result<ObjectMetadata>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Replaces key only while its current opaque token equals expected_etag.
A missing object or stale token returns
ObjectStoreError::PreconditionFailed; invalid keys, permission
failures, and transport failures are also returned.
Dyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".