diff --git a/src/aws/mod.rs b/src/aws/mod.rs index dd2cf6f0..030590ad 100644 --- a/src/aws/mod.rs +++ b/src/aws/mod.rs @@ -180,7 +180,11 @@ impl ObjectStore for AmazonS3 { match (mode, &self.client.config.conditional_put) { (PutMode::Overwrite, _) => request.idempotent(true).do_put().await, - (PutMode::Create, S3ConditionalPut::Disabled) => Err(Error::NotImplemented), + (PutMode::Create, S3ConditionalPut::Disabled) => Err(Error::NotImplemented { + operation: + "`put_opts` with mode `PutMode::Create` when conditional put is disabled".into(), + implementer: self.to_string(), + }), (PutMode::Create, S3ConditionalPut::ETagMatch) => { match request.header(&IF_NONE_MATCH, "*").do_put().await { // Technically If-None-Match should return NotModified but some stores, @@ -222,7 +226,12 @@ impl ObjectStore for AmazonS3 { r => r, } } - S3ConditionalPut::Disabled => Err(Error::NotImplemented), + S3ConditionalPut::Disabled => Err(Error::NotImplemented { + operation: + "`put_opts` with mode `PutMode::Update` when conditional put is disabled" + .into(), + implementer: self.to_string(), + }), } } } diff --git a/src/http/mod.rs b/src/http/mod.rs index e2410020..9e5af9a1 100644 --- a/src/http/mod.rs +++ b/src/http/mod.rs @@ -104,7 +104,10 @@ impl ObjectStore for HttpStore { ) -> Result { if opts.mode != PutMode::Overwrite { // TODO: Add support for If header - https://datatracker.ietf.org/doc/html/rfc2518#section-9.4 - return Err(crate::Error::NotImplemented); + return Err(crate::Error::NotImplemented { + operation: "`put_opts` with a mode other than `PutMode::Overwrite`".into(), + implementer: self.to_string(), + }); } let response = self.client.put(location, payload, opts.attributes).await?; @@ -125,7 +128,10 @@ impl ObjectStore for HttpStore { _location: &Path, _opts: PutMultipartOptions, ) -> Result> { - Err(crate::Error::NotImplemented) + Err(crate::Error::NotImplemented { + operation: "`put_multipart_opts`".into(), + implementer: self.to_string(), + }) } async fn get_opts(&self, location: &Path, options: GetOptions) -> Result { diff --git a/src/integration.rs b/src/integration.rs index bc79f696..5c601b5c 100644 --- a/src/integration.rs +++ b/src/integration.rs @@ -478,7 +478,7 @@ pub async fn put_get_attributes(integration: &dyn ObjectStore) { let r = integration.get(&path).await.unwrap(); assert_eq!(r.attributes, attributes); } - Err(Error::NotImplemented) => {} + Err(Error::NotImplemented { .. }) => {} Err(e) => panic!("{e}"), } @@ -491,7 +491,7 @@ pub async fn put_get_attributes(integration: &dyn ObjectStore) { let r = integration.get(&path).await.unwrap(); assert_eq!(r.attributes, attributes); } - Err(Error::NotImplemented) => {} + Err(Error::NotImplemented { .. }) => {} Err(e) => panic!("{e}"), } } @@ -606,7 +606,7 @@ pub async fn put_opts(storage: &dyn ObjectStore, supports_update: bool) { .put_opts(&path, "c".into(), PutMode::Update(v1.clone().into()).into()) .await .unwrap_err(); - assert!(matches!(err, Error::NotImplemented), "{err}"); + assert!(matches!(err, Error::NotImplemented { .. }), "{err}"); return; } diff --git a/src/lib.rs b/src/lib.rs index 6ffdf6d1..705e9305 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2032,8 +2032,17 @@ pub enum Error { }, /// Error when an operation is not implemented - #[error("Operation not yet implemented.")] - NotImplemented, + #[error("Operation {operation} not yet implemented by {implementer}.")] + NotImplemented { + /// What isn't implemented. Should include at least the method + /// name that was called; could also include other relevant + /// subcontexts. + operation: String, + + /// Which driver this is that hasn't implemented this operation, + /// to aid debugging in contexts that may be using multiple implementations. + implementer: String, + }, /// Error when the used credentials don't have enough permission /// to perform the requested operation diff --git a/src/local.rs b/src/local.rs index 003e7d70..8f18aa6b 100644 --- a/src/local.rs +++ b/src/local.rs @@ -330,11 +330,17 @@ impl ObjectStore for LocalFileSystem { opts: PutOptions, ) -> Result { if matches!(opts.mode, PutMode::Update(_)) { - return Err(crate::Error::NotImplemented); + return Err(crate::Error::NotImplemented { + operation: "`put_opts` with mode `PutMode::Update`".into(), + implementer: self.to_string(), + }); } if !opts.attributes.is_empty() { - return Err(crate::Error::NotImplemented); + return Err(crate::Error::NotImplemented { + operation: "`put_opts` with `opts.attributes` specified".into(), + implementer: self.to_string(), + }); } let path = self.path_to_filesystem(location)?; @@ -397,7 +403,10 @@ impl ObjectStore for LocalFileSystem { opts: PutMultipartOptions, ) -> Result> { if !opts.attributes.is_empty() { - return Err(crate::Error::NotImplemented); + return Err(crate::Error::NotImplemented { + operation: "`put_multipart_opts` with `opts.attributes` specified".into(), + implementer: self.to_string(), + }); } let dest = self.path_to_filesystem(location)?;