diff --git a/examples/BucketExists.cc b/examples/BucketExists.cc index 991d658..bfca548 100644 --- a/examples/BucketExists.cc +++ b/examples/BucketExists.cc @@ -33,18 +33,18 @@ int main() { args.bucket = "my-bucket"; // Call bucket exists. - minio::s3::BucketExistsResponse resp = client.BucketExists(args); + auto resp = client.BucketExists(args); // Handle response. if (resp) { - if (resp.exist) { + if (resp->exist) { std::cout << "my-bucket exists" << std::endl; } else { std::cout << "my-bucket does not exist" << std::endl; } } else { std::cout << "unable to do bucket existence check; " - << resp.Error().String() << std::endl; + << resp.error().String() << std::endl; } return 0; diff --git a/examples/ComposeObject.cc b/examples/ComposeObject.cc index 5461057..9bb41cf 100644 --- a/examples/ComposeObject.cc +++ b/examples/ComposeObject.cc @@ -48,13 +48,13 @@ int main() { args.sources = sources; // Call compose object. - minio::s3::ComposeObjectResponse resp = client.ComposeObject(args); + auto resp = client.ComposeObject(args); // Handle response. if (resp) { std::cout << "my-object is successfully created" << std::endl; } else { - std::cout << "unable to compose object; " << resp.Error().String() + std::cout << "unable to compose object; " << resp.error().String() << std::endl; } diff --git a/examples/CopyObject.cc b/examples/CopyObject.cc index 99780ed..754554f 100644 --- a/examples/CopyObject.cc +++ b/examples/CopyObject.cc @@ -39,14 +39,14 @@ int main() { args.source = source; // Call copy object. - minio::s3::CopyObjectResponse resp = client.CopyObject(args); + auto resp = client.CopyObject(args); // Handle response. if (resp) { std::cout << "my-object is successfully created from " << "my-src-bucket/my-src-object" << std::endl; } else { - std::cout << "unable to do copy object; " << resp.Error().String() + std::cout << "unable to do copy object; " << resp.error().String() << std::endl; } diff --git a/examples/DeleteBucketEncryption.cc b/examples/DeleteBucketEncryption.cc index e782205..50daeca 100644 --- a/examples/DeleteBucketEncryption.cc +++ b/examples/DeleteBucketEncryption.cc @@ -33,15 +33,14 @@ int main() { args.bucket = "my-bucket"; // Call delete bucket encryption. - minio::s3::DeleteBucketEncryptionResponse resp = - client.DeleteBucketEncryption(args); + auto resp = client.DeleteBucketEncryption(args); // Handle response. if (resp) { std::cout << "bucket encryption of my-bucket is deleted successfully" << std::endl; } else { - std::cout << "unable to delete bucket encryption; " << resp.Error().String() + std::cout << "unable to delete bucket encryption; " << resp.error().String() << std::endl; } diff --git a/examples/DeleteBucketLifecycle.cc b/examples/DeleteBucketLifecycle.cc index 573a45a..9e328e3 100644 --- a/examples/DeleteBucketLifecycle.cc +++ b/examples/DeleteBucketLifecycle.cc @@ -33,15 +33,14 @@ int main() { args.bucket = "my-bucket"; // Call delete bucket lifecycle. - minio::s3::DeleteBucketLifecycleResponse resp = - client.DeleteBucketLifecycle(args); + auto resp = client.DeleteBucketLifecycle(args); // Handle response. if (resp) { std::cout << "bucket lifecycle of my-bucket is deleted successfully" << std::endl; } else { - std::cout << "unable to delete bucket lifecycle; " << resp.Error().String() + std::cout << "unable to delete bucket lifecycle; " << resp.error().String() << std::endl; } diff --git a/examples/DeleteBucketNotification.cc b/examples/DeleteBucketNotification.cc index cbb3b3a..2e1df65 100644 --- a/examples/DeleteBucketNotification.cc +++ b/examples/DeleteBucketNotification.cc @@ -33,8 +33,7 @@ int main() { args.bucket = "my-bucket"; // Call delete bucket notification. - minio::s3::DeleteBucketNotificationResponse resp = - client.DeleteBucketNotification(args); + auto resp = client.DeleteBucketNotification(args); // Handle response. if (resp) { @@ -42,7 +41,7 @@ int main() { << std::endl; } else { std::cout << "unable to delete bucket notification; " - << resp.Error().String() << std::endl; + << resp.error().String() << std::endl; } return 0; diff --git a/examples/DeleteBucketPolicy.cc b/examples/DeleteBucketPolicy.cc index ed7b541..fc69752 100644 --- a/examples/DeleteBucketPolicy.cc +++ b/examples/DeleteBucketPolicy.cc @@ -33,14 +33,14 @@ int main() { args.bucket = "my-bucket"; // Call delete bucket policy. - minio::s3::DeleteBucketPolicyResponse resp = client.DeleteBucketPolicy(args); + auto resp = client.DeleteBucketPolicy(args); // Handle response. if (resp) { std::cout << "bucket policy of my-bucket is deleted successfully" << std::endl; } else { - std::cout << "unable to delete bucket policy; " << resp.Error().String() + std::cout << "unable to delete bucket policy; " << resp.error().String() << std::endl; } diff --git a/examples/DeleteBucketReplication.cc b/examples/DeleteBucketReplication.cc index e782205..50daeca 100644 --- a/examples/DeleteBucketReplication.cc +++ b/examples/DeleteBucketReplication.cc @@ -33,15 +33,14 @@ int main() { args.bucket = "my-bucket"; // Call delete bucket encryption. - minio::s3::DeleteBucketEncryptionResponse resp = - client.DeleteBucketEncryption(args); + auto resp = client.DeleteBucketEncryption(args); // Handle response. if (resp) { std::cout << "bucket encryption of my-bucket is deleted successfully" << std::endl; } else { - std::cout << "unable to delete bucket encryption; " << resp.Error().String() + std::cout << "unable to delete bucket encryption; " << resp.error().String() << std::endl; } diff --git a/examples/DeleteBucketTags.cc b/examples/DeleteBucketTags.cc index 1cc21b6..9efbc18 100644 --- a/examples/DeleteBucketTags.cc +++ b/examples/DeleteBucketTags.cc @@ -33,14 +33,14 @@ int main() { args.bucket = "my-bucket"; // Call delete bucket tags. - minio::s3::DeleteBucketTagsResponse resp = client.DeleteBucketTags(args); + auto resp = client.DeleteBucketTags(args); // Handle response. if (resp) { std::cout << "bucket tags of my-bucket is deleted successfully" << std::endl; } else { - std::cout << "unable to delete bucket tags; " << resp.Error().String() + std::cout << "unable to delete bucket tags; " << resp.error().String() << std::endl; } diff --git a/examples/DeleteObjectLockConfig.cc b/examples/DeleteObjectLockConfig.cc index 4ac9c85..23b283e 100644 --- a/examples/DeleteObjectLockConfig.cc +++ b/examples/DeleteObjectLockConfig.cc @@ -33,8 +33,7 @@ int main() { args.bucket = "my-bucket"; // Call delete object lock config. - minio::s3::DeleteObjectLockConfigResponse resp = - client.DeleteObjectLockConfig(args); + auto resp = client.DeleteObjectLockConfig(args); // Handle response. if (resp) { @@ -42,7 +41,7 @@ int main() { << std::endl; } else { std::cout << "unable to delete object lock configuration; " - << resp.Error().String() << std::endl; + << resp.error().String() << std::endl; } return 0; diff --git a/examples/DeleteObjectTags.cc b/examples/DeleteObjectTags.cc index 27f506a..b0606c7 100644 --- a/examples/DeleteObjectTags.cc +++ b/examples/DeleteObjectTags.cc @@ -34,14 +34,14 @@ int main() { args.object = "my-object"; // Call delete object tags. - minio::s3::DeleteObjectTagsResponse resp = client.DeleteObjectTags(args); + auto resp = client.DeleteObjectTags(args); // Handle response. if (resp) { std::cout << "object tags of my-object is deleted successfully" << std::endl; } else { - std::cout << "unable to delete object tags; " << resp.Error().String() + std::cout << "unable to delete object tags; " << resp.error().String() << std::endl; } diff --git a/examples/DisableObjectLegalHold.cc b/examples/DisableObjectLegalHold.cc index f9e9e5c..327fdd2 100644 --- a/examples/DisableObjectLegalHold.cc +++ b/examples/DisableObjectLegalHold.cc @@ -34,8 +34,7 @@ int main() { args.object = "my-object"; // Call disable object legal hold. - minio::s3::DisableObjectLegalHoldResponse resp = - client.DisableObjectLegalHold(args); + auto resp = client.DisableObjectLegalHold(args); // Handle response. if (resp) { @@ -43,7 +42,7 @@ int main() { << std::endl; } else { std::cout << "unable to disable object legal hold; " - << resp.Error().String() << std::endl; + << resp.error().String() << std::endl; } return 0; diff --git a/examples/DownloadObject.cc b/examples/DownloadObject.cc index 8a28375..22b1a61 100644 --- a/examples/DownloadObject.cc +++ b/examples/DownloadObject.cc @@ -35,14 +35,14 @@ int main() { args.filename = "my-object.csv"; // Call download object. - minio::s3::DownloadObjectResponse resp = client.DownloadObject(args); + auto resp = client.DownloadObject(args); // Handle response. if (resp) { std::cout << "my-object is successfully downloaded to my-object.csv" << std::endl; } else { - std::cout << "unable to download object; " << resp.Error().String() + std::cout << "unable to download object; " << resp.error().String() << std::endl; } diff --git a/examples/EnableObjectLegalHold.cc b/examples/EnableObjectLegalHold.cc index d7b7a98..f707c53 100644 --- a/examples/EnableObjectLegalHold.cc +++ b/examples/EnableObjectLegalHold.cc @@ -34,14 +34,13 @@ int main() { args.object = "my-object"; // Call enable object legal hold. - minio::s3::EnableObjectLegalHoldResponse resp = - client.EnableObjectLegalHold(args); + auto resp = client.EnableObjectLegalHold(args); // Handle response. if (resp) { std::cout << "legal hold on my-object is enabled successfully" << std::endl; } else { - std::cout << "unable to enable object legal hold; " << resp.Error().String() + std::cout << "unable to enable object legal hold; " << resp.error().String() << std::endl; } diff --git a/examples/GetBucketEncryption.cc b/examples/GetBucketEncryption.cc index 391ad92..106b029 100644 --- a/examples/GetBucketEncryption.cc +++ b/examples/GetBucketEncryption.cc @@ -33,16 +33,15 @@ int main() { args.bucket = "my-bucket"; // Call get bucket encryption. - minio::s3::GetBucketEncryptionResponse resp = - client.GetBucketEncryption(args); + auto resp = client.GetBucketEncryption(args); // Handle response. if (resp) { - std::cout << "SSE Algorithm: " << resp.config.sse_algorithm << std::endl; - std::cout << "KMS Master Key ID: " << resp.config.kms_master_key_id + std::cout << "SSE Algorithm: " << resp->config.sse_algorithm << std::endl; + std::cout << "KMS Master Key ID: " << resp->config.kms_master_key_id << std::endl; } else { - std::cout << "unable to get bucket encryption; " << resp.Error().String() + std::cout << "unable to get bucket encryption; " << resp.error().String() << std::endl; } diff --git a/examples/GetBucketLifecycle.cc b/examples/GetBucketLifecycle.cc index eaa800b..cb637b4 100644 --- a/examples/GetBucketLifecycle.cc +++ b/examples/GetBucketLifecycle.cc @@ -33,14 +33,14 @@ int main() { args.bucket = "my-bucket"; // Call get bucket lifecycle. - minio::s3::GetBucketLifecycleResponse resp = client.GetBucketLifecycle(args); + auto resp = client.GetBucketLifecycle(args); // Handle response. if (resp) { - std::cout << "Lifecycle configuration: " << resp.config.ToXML() + std::cout << "Lifecycle configuration: " << resp->config.ToXML() << std::endl; } else { - std::cout << "unable to get bucket lifecycle; " << resp.Error().String() + std::cout << "unable to get bucket lifecycle; " << resp.error().String() << std::endl; } diff --git a/examples/GetBucketNotification.cc b/examples/GetBucketNotification.cc index 8aac6c9..0342a9b 100644 --- a/examples/GetBucketNotification.cc +++ b/examples/GetBucketNotification.cc @@ -33,14 +33,13 @@ int main() { args.bucket = "my-bucket"; // Call get bucket notification. - minio::s3::GetBucketNotificationResponse resp = - client.GetBucketNotification(args); + auto resp = client.GetBucketNotification(args); // Handle response. if (resp) { - std::cout << "Bucket notification: " << resp.config.ToXML() << std::endl; + std::cout << "Bucket notification: " << resp->config.ToXML() << std::endl; } else { - std::cout << "unable to get bucket notification; " << resp.Error().String() + std::cout << "unable to get bucket notification; " << resp.error().String() << std::endl; } diff --git a/examples/GetBucketPolicy.cc b/examples/GetBucketPolicy.cc index 9283c94..d666088 100644 --- a/examples/GetBucketPolicy.cc +++ b/examples/GetBucketPolicy.cc @@ -33,13 +33,13 @@ int main() { args.bucket = "my-bucket"; // Call get bucket policy. - minio::s3::GetBucketPolicyResponse resp = client.GetBucketPolicy(args); + auto resp = client.GetBucketPolicy(args); // Handle response. if (resp) { - std::cout << "Bucket policy: " << resp.policy << std::endl; + std::cout << "Bucket policy: " << resp->policy << std::endl; } else { - std::cout << "unable to get bucket policy; " << resp.Error().String() + std::cout << "unable to get bucket policy; " << resp.error().String() << std::endl; } diff --git a/examples/GetBucketReplication.cc b/examples/GetBucketReplication.cc index 391ad92..106b029 100644 --- a/examples/GetBucketReplication.cc +++ b/examples/GetBucketReplication.cc @@ -33,16 +33,15 @@ int main() { args.bucket = "my-bucket"; // Call get bucket encryption. - minio::s3::GetBucketEncryptionResponse resp = - client.GetBucketEncryption(args); + auto resp = client.GetBucketEncryption(args); // Handle response. if (resp) { - std::cout << "SSE Algorithm: " << resp.config.sse_algorithm << std::endl; - std::cout << "KMS Master Key ID: " << resp.config.kms_master_key_id + std::cout << "SSE Algorithm: " << resp->config.sse_algorithm << std::endl; + std::cout << "KMS Master Key ID: " << resp->config.kms_master_key_id << std::endl; } else { - std::cout << "unable to get bucket encryption; " << resp.Error().String() + std::cout << "unable to get bucket encryption; " << resp.error().String() << std::endl; } diff --git a/examples/GetBucketTags.cc b/examples/GetBucketTags.cc index 552fd2e..c73335b 100644 --- a/examples/GetBucketTags.cc +++ b/examples/GetBucketTags.cc @@ -33,16 +33,16 @@ int main() { args.bucket = "my-bucket"; // Call get bucket tags. - minio::s3::GetBucketTagsResponse resp = client.GetBucketTags(args); + auto resp = client.GetBucketTags(args); // Handle response. if (resp) { std::cout << "Bucket tags: " << std::endl; - for (auto& [key, value] : resp.tags) { + for (auto& [key, value] : resp->tags) { std::cout << "Key: " << key << ", " << "Value: " << value << std::endl; } } else { - std::cout << "unable to get bucket tags; " << resp.Error().String() + std::cout << "unable to get bucket tags; " << resp.error().String() << std::endl; } diff --git a/examples/GetBucketVersioning.cc b/examples/GetBucketVersioning.cc index ee9801b..b2b46c5 100644 --- a/examples/GetBucketVersioning.cc +++ b/examples/GetBucketVersioning.cc @@ -33,15 +33,14 @@ int main() { args.bucket = "my-bucket"; // Call get bucket versioning. - minio::s3::GetBucketVersioningResponse resp = - client.GetBucketVersioning(args); + auto resp = client.GetBucketVersioning(args); // Handle response. if (resp) { - std::cout << "Status: " << resp.Status() << std::endl; - std::cout << "MFA Delete: " << resp.MfaDelete() << std::endl; + std::cout << "Status: " << resp->Status() << std::endl; + std::cout << "MFA Delete: " << resp->MfaDelete() << std::endl; } else { - std::cout << "unable to get bucket versioning; " << resp.Error().String() + std::cout << "unable to get bucket versioning; " << resp.error().String() << std::endl; } diff --git a/examples/GetObject.cc b/examples/GetObject.cc index ddced56..7544832 100644 --- a/examples/GetObject.cc +++ b/examples/GetObject.cc @@ -38,14 +38,14 @@ int main() { }; // Call get object. - minio::s3::GetObjectResponse resp = client.GetObject(args); + auto resp = client.GetObject(args); // Handle response. if (resp) { std::cout << std::endl << "data of my-object is received successfully" << std::endl; } else { - std::cout << "unable to get object; " << resp.Error().String() << std::endl; + std::cout << "unable to get object; " << resp.error().String() << std::endl; } return 0; diff --git a/examples/GetObjectLockConfig.cc b/examples/GetObjectLockConfig.cc index 9d2782e..c9533c3 100644 --- a/examples/GetObjectLockConfig.cc +++ b/examples/GetObjectLockConfig.cc @@ -33,28 +33,27 @@ int main() { args.bucket = "my-bucket"; // Call get object lock config. - minio::s3::GetObjectLockConfigResponse resp = - client.GetObjectLockConfig(args); + auto resp = client.GetObjectLockConfig(args); // Handle response. if (resp) { std::cout << "Object Lock Configuration:" << std::endl; - if (minio::s3::IsRetentionModeValid(resp.config.retention_mode)) { + if (minio::s3::IsRetentionModeValid(resp->config.retention_mode)) { std::cout << "Retention Mode: " - << minio::s3::RetentionModeToString(resp.config.retention_mode) + << minio::s3::RetentionModeToString(resp->config.retention_mode) << std::endl; - if (resp.config.retention_duration_days) { - std::cout << "Retention Days: " << resp.config.retention_duration_days + if (resp->config.retention_duration_days) { + std::cout << "Retention Days: " << resp->config.retention_duration_days << std::endl; } - if (resp.config.retention_duration_years) { - std::cout << "Retention Years: " << resp.config.retention_duration_years - << std::endl; + if (resp->config.retention_duration_years) { + std::cout << "Retention Years: " + << resp->config.retention_duration_years << std::endl; } } } else { std::cout << "unable to get object lock configuration; " - << resp.Error().String() << std::endl; + << resp.error().String() << std::endl; } return 0; diff --git a/examples/GetObjectProgress.cc b/examples/GetObjectProgress.cc index 5d089dd..8cd8af8 100644 --- a/examples/GetObjectProgress.cc +++ b/examples/GetObjectProgress.cc @@ -49,14 +49,14 @@ int main() { }; // Call get object. - minio::s3::GetObjectResponse resp = client.GetObject(args); + auto resp = client.GetObject(args); // Handle response. if (resp) { std::cout << std::endl << "data of my-object is received successfully" << std::endl; } else { - std::cout << "unable to get object; " << resp.Error().String() << std::endl; + std::cout << "unable to get object; " << resp.error().String() << std::endl; } return 0; diff --git a/examples/GetObjectRetention.cc b/examples/GetObjectRetention.cc index 4a9be0d..19c36d3 100644 --- a/examples/GetObjectRetention.cc +++ b/examples/GetObjectRetention.cc @@ -34,17 +34,17 @@ int main() { args.object = "my-object"; // Call get object retention. - minio::s3::GetObjectRetentionResponse resp = client.GetObjectRetention(args); + auto resp = client.GetObjectRetention(args); // Handle response. if (resp) { std::cout << "Retention Mode: " - << minio::s3::RetentionModeToString(resp.retention_mode) + << minio::s3::RetentionModeToString(resp->retention_mode) << std::endl; std::cout << "Retain Until Date: " - << resp.retain_until_date.ToHttpHeaderValue() << std::endl; + << resp->retain_until_date.ToHttpHeaderValue() << std::endl; } else { - std::cout << "unable to get object retention; " << resp.Error().String() + std::cout << "unable to get object retention; " << resp.error().String() << std::endl; } diff --git a/examples/GetObjectTags.cc b/examples/GetObjectTags.cc index 909b1c0..14556ad 100644 --- a/examples/GetObjectTags.cc +++ b/examples/GetObjectTags.cc @@ -34,16 +34,16 @@ int main() { args.object = "my-object"; // Call get object tags. - minio::s3::GetObjectTagsResponse resp = client.GetObjectTags(args); + auto resp = client.GetObjectTags(args); // Handle response. if (resp) { std::cout << "Object tags: " << std::endl; - for (auto& [key, value] : resp.tags) { + for (auto& [key, value] : resp->tags) { std::cout << "Key: " << key << ", " << "Value: " << value << std::endl; } } else { - std::cout << "unable to get object tags; " << resp.Error().String() + std::cout << "unable to get object tags; " << resp.error().String() << std::endl; } diff --git a/examples/GetPresignedObjectUrl.cc b/examples/GetPresignedObjectUrl.cc index 1a80dc5..c2f42cc 100644 --- a/examples/GetPresignedObjectUrl.cc +++ b/examples/GetPresignedObjectUrl.cc @@ -36,14 +36,13 @@ int main() { args.expiry_seconds = 60 * 60 * 24; // 1 day. // Call get presigned object url. - minio::s3::GetPresignedObjectUrlResponse resp = - client.GetPresignedObjectUrl(args); + auto resp = client.GetPresignedObjectUrl(args); // Handle response. if (resp) { - std::cout << "presigned URL to get object: " << resp.url << std::endl; + std::cout << "presigned URL to get object: " << resp->url << std::endl; } else { - std::cout << "unable to get presigned object url; " << resp.Error().String() + std::cout << "unable to get presigned object url; " << resp.error().String() << std::endl; } diff --git a/examples/GetPresignedPostFormData.cc b/examples/GetPresignedPostFormData.cc index c084d8d..216eeae 100644 --- a/examples/GetPresignedPostFormData.cc +++ b/examples/GetPresignedPostFormData.cc @@ -36,20 +36,20 @@ int main() { policy.AddContentLengthRangeCondition(1 * 1024 * 1024, 10 * 1024 * 1024); // Call get presigned post form data. - minio::s3::GetPresignedPostFormDataResponse resp = - client.GetPresignedPostFormData(policy); + auto resp = client.GetPresignedPostFormData(policy); // Handle response. if (resp) { std::string fields; - for (auto& [key, value] : resp.form_data) fields += key + "=" + value + " "; + for (auto& [key, value] : resp->form_data) + fields += key + "=" + value + " "; fields += "-F file=@"; std::cout << "Example CURL command to use form-data:" << std::endl << "curl -X POST https://play.min.io/my-bucket " << fields << std::endl; } else { std::cout << "unable to get presigned post form data; " - << resp.Error().String() << std::endl; + << resp.error().String() << std::endl; } return 0; diff --git a/examples/GetPutRDMA.cc b/examples/GetPutRDMA.cc index ee92f0e..cd7bbf8 100644 --- a/examples/GetPutRDMA.cc +++ b/examples/GetPutRDMA.cc @@ -172,12 +172,12 @@ int main(int argc, char *argv[]) { pargs.bucket = "my-bucket"; pargs.object = "my-object"; - minio::s3::PutObjectResponse presp = client.PutObject(pargs); + auto presp = client.PutObject(pargs); if (presp) { std::cout << std::endl - << "data uploaded successfully " << presp.etag << std::endl; + << "data uploaded successfully " << presp->etag << std::endl; } else { - std::cout << "unable to get object; " << presp.Error().String() + std::cout << "unable to get object; " << presp.error().String() << std::endl; } @@ -191,12 +191,12 @@ int main(int argc, char *argv[]) { args.bucket = "my-bucket"; args.object = "my-object"; - minio::s3::GetObjectResponse resp = client.GetObject(args); + auto resp = client.GetObject(args); if (resp) { std::cout << std::endl << "data of my-object is received successfully" << std::endl; } else { - std::cout << "unable to get object; " << resp.Error().String() << std::endl; + std::cout << "unable to get object; " << resp.error().String() << std::endl; } char *hostptr = (char *)malloc(bufsize); diff --git a/examples/IsObjectLegalHoldEnabled.cc b/examples/IsObjectLegalHoldEnabled.cc index 10f59ec..057011a 100644 --- a/examples/IsObjectLegalHoldEnabled.cc +++ b/examples/IsObjectLegalHoldEnabled.cc @@ -34,15 +34,14 @@ int main() { args.object = "my-object"; // Call is object legal hold enabled. - minio::s3::IsObjectLegalHoldEnabledResponse resp = - client.IsObjectLegalHoldEnabled(args); + auto resp = client.IsObjectLegalHoldEnabled(args); // Handle response. if (resp) { - std::cout << "legal hold: " << (resp.enabled ? "ON" : "OFF") << std::endl; + std::cout << "legal hold: " << (resp->enabled ? "ON" : "OFF") << std::endl; } else { std::cout << "unable to do is object legal hold enabled; " - << resp.Error().String() << std::endl; + << resp.error().String() << std::endl; } return 0; diff --git a/examples/ListBuckets.cc b/examples/ListBuckets.cc index 20a2463..d79ab12 100644 --- a/examples/ListBuckets.cc +++ b/examples/ListBuckets.cc @@ -29,16 +29,16 @@ int main() { minio::s3::Client client(base_url, &provider); // Call list buckets. - minio::s3::ListBucketsResponse resp = client.ListBuckets(); + auto resp = client.ListBuckets(); // Handle response. if (resp) { - for (auto& bucket : resp.buckets) { + for (auto& bucket : resp->buckets) { std::cout << "Bucket: " << bucket.name << "; Creation date: " << bucket.creation_date.ToHttpHeaderValue() << std::endl; } } else { - std::cout << "unable to list buckets; " << resp.Error().String() + std::cout << "unable to list buckets; " << resp.error().String() << std::endl; } diff --git a/examples/ListObjects.cc b/examples/ListObjects.cc index e99b8b9..ce50d9d 100644 --- a/examples/ListObjects.cc +++ b/examples/ListObjects.cc @@ -33,35 +33,28 @@ int main() { args.bucket = "my-bucket"; // Call list objects. - minio::s3::ListObjectsResult result = client.ListObjects(args); + auto result = client.ListObjects(args); for (; result; result++) { - minio::s3::Item item = *result; - if (item) { - std::cout << "Name: " << item.name << std::endl; - std::cout << "Version ID: " << item.version_id << std::endl; - std::cout << "ETag: " << item.etag << std::endl; - std::cout << "Size: " << item.size << std::endl; - std::cout << "Last Modified: " << item.last_modified << std::endl; - std::cout << "Delete Marker: " - << minio::utils::BoolToString(item.is_delete_marker) - << std::endl; - std::cout << "User Metadata: " << std::endl; - for (auto& [key, value] : item.user_metadata) { - std::cout << " " << key << ": " << value << std::endl; - } - std::cout << "Owner ID: " << item.owner_id << std::endl; - std::cout << "Owner Name: " << item.owner_name << std::endl; - std::cout << "Storage Class: " << item.storage_class << std::endl; - std::cout << "Is Latest: " << minio::utils::BoolToString(item.is_latest) - << std::endl; - std::cout << "Is Prefix: " << minio::utils::BoolToString(item.is_prefix) - << std::endl; - std::cout << "---" << std::endl; - } else { - std::cout << "unable to listobjects; " << item.Error().String() - << std::endl; - break; + auto item = *result; + std::cout << "Name: " << item.name << std::endl; + std::cout << "Version ID: " << item.version_id << std::endl; + std::cout << "ETag: " << item.etag << std::endl; + std::cout << "Size: " << item.size << std::endl; + std::cout << "Last Modified: " << item.last_modified << std::endl; + std::cout << "Delete Marker: " + << minio::utils::BoolToString(item.is_delete_marker) << std::endl; + std::cout << "User Metadata: " << std::endl; + for (auto& [key, value] : item.user_metadata) { + std::cout << " " << key << ": " << value << std::endl; } + std::cout << "Owner ID: " << item.owner_id << std::endl; + std::cout << "Owner Name: " << item.owner_name << std::endl; + std::cout << "Storage Class: " << item.storage_class << std::endl; + std::cout << "Is Latest: " << minio::utils::BoolToString(item.is_latest) + << std::endl; + std::cout << "Is Prefix: " << minio::utils::BoolToString(item.is_prefix) + << std::endl; + std::cout << "---" << std::endl; } return 0; diff --git a/examples/ListenBucketNotification.cc b/examples/ListenBucketNotification.cc index 7d56785..00fbead 100644 --- a/examples/ListenBucketNotification.cc +++ b/examples/ListenBucketNotification.cc @@ -41,13 +41,12 @@ int main() { }; // Call listen bucket notification. - minio::s3::ListenBucketNotificationResponse resp = - client.ListenBucketNotification(args); + auto resp = client.ListenBucketNotification(args); // Handle response. if (!resp) { std::cout << "unable to do listen bucket notification; " - << resp.Error().String() << std::endl; + << resp.error().String() << std::endl; } return 0; diff --git a/examples/MakeBucket.cc b/examples/MakeBucket.cc index 4013dbd..1900105 100644 --- a/examples/MakeBucket.cc +++ b/examples/MakeBucket.cc @@ -33,13 +33,13 @@ int main() { args.bucket = "my-bucket"; // Call make bucket. - minio::s3::MakeBucketResponse resp = client.MakeBucket(args); + auto resp = client.MakeBucket(args); // Handle response. if (resp) { std::cout << "my-bucket is created successfully" << std::endl; } else { - std::cout << "unable to create bucket; " << resp.Error().String() + std::cout << "unable to create bucket; " << resp.error().String() << std::endl; } diff --git a/examples/PutObject.cc b/examples/PutObject.cc index e3e481b..74b88c7 100644 --- a/examples/PutObject.cc +++ b/examples/PutObject.cc @@ -63,14 +63,14 @@ int main(int argc, char* argv[]) { args.object = "my-object"; // Call put object. - minio::s3::PutObjectResponse resp = client.PutObject(args); + auto resp = client.PutObject(args); // Handle response. if (resp) { - std::cout << "my-object is successfully created etag=" << resp.etag << " " + std::cout << "my-object is successfully created etag=" << resp->etag << " " << std::endl; } else { - std::cout << "unable to do put object; " << resp.Error().String() + std::cout << "unable to do put object; " << resp.error().String() << std::endl; } diff --git a/examples/PutObjectProgress.cc b/examples/PutObjectProgress.cc index a9631aa..0a9d785 100644 --- a/examples/PutObjectProgress.cc +++ b/examples/PutObjectProgress.cc @@ -55,13 +55,13 @@ int main() { }; // Call put object. - minio::s3::PutObjectResponse resp = client.PutObject(args); + auto resp = client.PutObject(args); // Handle response. if (resp) { std::cout << "my-object is successfully created" << std::endl; } else { - std::cout << "unable to do put object; " << resp.Error().String() + std::cout << "unable to do put object; " << resp.error().String() << std::endl; } diff --git a/examples/RemoveBucket.cc b/examples/RemoveBucket.cc index 302df27..cb89fba 100644 --- a/examples/RemoveBucket.cc +++ b/examples/RemoveBucket.cc @@ -33,13 +33,13 @@ int main() { args.bucket = "my-bucket"; // Call remove bucket. - minio::s3::RemoveBucketResponse resp = client.RemoveBucket(args); + auto resp = client.RemoveBucket(args); // Handle response. if (resp) { std::cout << "my-bucket is removed successfully" << std::endl; } else { - std::cout << "unable to remove bucket; " << resp.Error().String() + std::cout << "unable to remove bucket; " << resp.error().String() << std::endl; } diff --git a/examples/RemoveObject.cc b/examples/RemoveObject.cc index 676a64f..1bbe109 100644 --- a/examples/RemoveObject.cc +++ b/examples/RemoveObject.cc @@ -34,13 +34,13 @@ int main() { args.object = "my-object"; // Call remove object. - minio::s3::RemoveObjectResponse resp = client.RemoveObject(args); + auto resp = client.RemoveObject(args); // Handle response. if (resp) { std::cout << "my-object is removed successfully" << std::endl; } else { - std::cout << "unable to remove object; " << resp.Error().String() + std::cout << "unable to remove object; " << resp.error().String() << std::endl; } diff --git a/examples/RemoveObjects.cc b/examples/RemoveObjects.cc index cfe650b..fdf9211 100644 --- a/examples/RemoveObjects.cc +++ b/examples/RemoveObjects.cc @@ -47,12 +47,12 @@ int main() { }; // Call remove objects. - minio::s3::RemoveObjectsResult result = client.RemoveObjects(args); + auto result = client.RemoveObjects(args); for (; result; result++) { - minio::s3::DeleteError err = *result; - if (!err) { - std::cout << "unable to do remove objects; " << err.Error().String() - << std::endl; + auto err = *result; + if (!err.code.empty() || !err.message.empty()) { + std::cout << "unable to do remove objects; " << err.code << ": " + << err.message << std::endl; break; } diff --git a/examples/SelectObjectContent.cc b/examples/SelectObjectContent.cc index 9c75109..6602c9d 100644 --- a/examples/SelectObjectContent.cc +++ b/examples/SelectObjectContent.cc @@ -31,11 +31,11 @@ int main() { std::string expression = "select * from S3Object"; minio::s3::CsvInputSerialization csv_input; - minio::s3::FileHeaderInfo file_header_info = minio::s3::FileHeaderInfo::kUse; + auto file_header_info = minio::s3::FileHeaderInfo::kUse; csv_input.file_header_info = std::make_shared(file_header_info); minio::s3::CsvOutputSerialization csv_output; - minio::s3::QuoteFields quote_fields = minio::s3::QuoteFields::kAsNeeded; + auto quote_fields = minio::s3::QuoteFields::kAsNeeded; csv_output.quote_fields = std::make_shared(quote_fields); minio::s3::SelectRequest request(expression, &csv_input, &csv_output); @@ -53,13 +53,12 @@ int main() { minio::s3::SelectObjectContentArgs args(request, func); args.bucket = "my-bucket"; args.object = "my-object.csv"; - minio::s3::SelectObjectContentResponse resp = - client.SelectObjectContent(args); + auto resp = client.SelectObjectContent(args); if (resp) { std::cout << "records retrieved" << std::endl; std::cout << records << std::endl; } else { - std::cout << "unable to do select object content; " << resp.Error().String() + std::cout << "unable to do select object content; " << resp.error().String() << std::endl; } diff --git a/examples/SetBucketEncryption.cc b/examples/SetBucketEncryption.cc index f979642..794bc13 100644 --- a/examples/SetBucketEncryption.cc +++ b/examples/SetBucketEncryption.cc @@ -29,19 +29,18 @@ int main() { minio::s3::Client client(base_url, &provider); // Create set bucket encryption arguments. - minio::s3::SseConfig sseS3Config = minio::s3::SseConfig::S3(); + auto sseS3Config = minio::s3::SseConfig::S3(); minio::s3::SetBucketEncryptionArgs args(sseS3Config); args.bucket = "my-bucket"; // Call set bucket encryption. - minio::s3::SetBucketEncryptionResponse resp = - client.SetBucketEncryption(args); + auto resp = client.SetBucketEncryption(args); // Handle response. if (resp) { std::cout << "Bucket encryption is set successfully" << std::endl; } else { - std::cout << "unable to set bucket encryption; " << resp.Error().String() + std::cout << "unable to set bucket encryption; " << resp.error().String() << std::endl; } diff --git a/examples/SetBucketLifecycle.cc b/examples/SetBucketLifecycle.cc index 7567e6b..b49ea44 100644 --- a/examples/SetBucketLifecycle.cc +++ b/examples/SetBucketLifecycle.cc @@ -52,13 +52,13 @@ int main() { args.bucket = "my-bucket"; // Call set bucket lifecycle. - minio::s3::SetBucketLifecycleResponse resp = client.SetBucketLifecycle(args); + auto resp = client.SetBucketLifecycle(args); // Handle response. if (resp) { std::cout << "Bucket lifecycle is set successfully" << std::endl; } else { - std::cout << "unable to set bucket lifecycle; " << resp.Error().String() + std::cout << "unable to set bucket lifecycle; " << resp.error().String() << std::endl; } diff --git a/examples/SetBucketNotification.cc b/examples/SetBucketNotification.cc index aefd5ff..fc813f0 100644 --- a/examples/SetBucketNotification.cc +++ b/examples/SetBucketNotification.cc @@ -41,14 +41,13 @@ int main() { args.bucket = "my-bucket"; // Call set bucket notification. - minio::s3::SetBucketNotificationResponse resp = - client.SetBucketNotification(args); + auto resp = client.SetBucketNotification(args); // Handle response. if (resp) { std::cout << "Bucket notification is set successfully" << std::endl; } else { - std::cout << "unable to set bucket notification; " << resp.Error().String() + std::cout << "unable to set bucket notification; " << resp.error().String() << std::endl; } diff --git a/examples/SetBucketPolicy.cc b/examples/SetBucketPolicy.cc index dc3df74..4b21138 100644 --- a/examples/SetBucketPolicy.cc +++ b/examples/SetBucketPolicy.cc @@ -49,13 +49,13 @@ int main() { "}"; // Call set bucket policy. - minio::s3::SetBucketPolicyResponse resp = client.SetBucketPolicy(args); + auto resp = client.SetBucketPolicy(args); // Handle response. if (resp) { std::cout << "Bucket policy is set successfully" << std::endl; } else { - std::cout << "unable to set bucket policy; " << resp.Error().String() + std::cout << "unable to set bucket policy; " << resp.error().String() << std::endl; } diff --git a/examples/SetBucketReplication.cc b/examples/SetBucketReplication.cc index 198b055..f991aba 100644 --- a/examples/SetBucketReplication.cc +++ b/examples/SetBucketReplication.cc @@ -47,14 +47,13 @@ int main() { args.bucket = "my-bucket"; // Call set bucket replication. - minio::s3::SetBucketReplicationResponse resp = - client.SetBucketReplication(args); + auto resp = client.SetBucketReplication(args); // Handle response. if (resp) { std::cout << "Bucket replication is set successfully" << std::endl; } else { - std::cout << "unable to set bucket replication; " << resp.Error().String() + std::cout << "unable to set bucket replication; " << resp.error().String() << std::endl; } diff --git a/examples/SetBucketTags.cc b/examples/SetBucketTags.cc index b89aabb..5513a5b 100644 --- a/examples/SetBucketTags.cc +++ b/examples/SetBucketTags.cc @@ -35,13 +35,13 @@ int main() { args.tags["User"] = "jsmith"; // Call set bucket tags. - minio::s3::SetBucketTagsResponse resp = client.SetBucketTags(args); + auto resp = client.SetBucketTags(args); // Handle response. if (resp) { std::cout << "Bucket tags are set successfully" << std::endl; } else { - std::cout << "unable to set bucket tags; " << resp.Error().String() + std::cout << "unable to set bucket tags; " << resp.error().String() << std::endl; } diff --git a/examples/SetBucketVersioning.cc b/examples/SetBucketVersioning.cc index 982313c..8281fa5 100644 --- a/examples/SetBucketVersioning.cc +++ b/examples/SetBucketVersioning.cc @@ -34,14 +34,13 @@ int main() { args.status = true; // Call set bucket versioning. - minio::s3::SetBucketVersioningResponse resp = - client.SetBucketVersioning(args); + auto resp = client.SetBucketVersioning(args); // Handle response. if (resp) { std::cout << "Bucket versioning is enabled successfully" << std::endl; } else { - std::cout << "unable to set bucket versioning; " << resp.Error().String() + std::cout << "unable to set bucket versioning; " << resp.error().String() << std::endl; } diff --git a/examples/SetObjectLockConfig.cc b/examples/SetObjectLockConfig.cc index c60db66..e6beeae 100644 --- a/examples/SetObjectLockConfig.cc +++ b/examples/SetObjectLockConfig.cc @@ -35,15 +35,14 @@ int main() { args.config.retention_duration_days = minio::s3::Integer(30); // Call set object lock config. - minio::s3::SetObjectLockConfigResponse resp = - client.SetObjectLockConfig(args); + auto resp = client.SetObjectLockConfig(args); // Handle response. if (resp) { std::cout << "Object lock configuration is set successfully" << std::endl; } else { std::cout << "unable to do object lock configuration; " - << resp.Error().String() << std::endl; + << resp.error().String() << std::endl; } return 0; diff --git a/examples/SetObjectRetention.cc b/examples/SetObjectRetention.cc index 57ab6f4..95b9446 100644 --- a/examples/SetObjectRetention.cc +++ b/examples/SetObjectRetention.cc @@ -38,13 +38,13 @@ int main() { args.retain_until_date = tomorrow; // Call set object retention. - minio::s3::SetObjectRetentionResponse resp = client.SetObjectRetention(args); + auto resp = client.SetObjectRetention(args); // Handle response. if (resp) { std::cout << "Object retention are set successfully" << std::endl; } else { - std::cout << "unable to set object retention; " << resp.Error().String() + std::cout << "unable to set object retention; " << resp.error().String() << std::endl; } diff --git a/examples/SetObjectTags.cc b/examples/SetObjectTags.cc index 82914e2..eceacf4 100644 --- a/examples/SetObjectTags.cc +++ b/examples/SetObjectTags.cc @@ -36,13 +36,13 @@ int main() { args.tags["User"] = "jsmith"; // Call set object tags. - minio::s3::SetObjectTagsResponse resp = client.SetObjectTags(args); + auto resp = client.SetObjectTags(args); // Handle response. if (resp) { std::cout << "Object tags are set successfully" << std::endl; } else { - std::cout << "unable to set object tags; " << resp.Error().String() + std::cout << "unable to set object tags; " << resp.error().String() << std::endl; } diff --git a/examples/StatObject.cc b/examples/StatObject.cc index 606a41b..2da82dd 100644 --- a/examples/StatObject.cc +++ b/examples/StatObject.cc @@ -34,44 +34,44 @@ int main() { args.object = "my-object"; // Call stat object. - minio::s3::StatObjectResponse resp = client.StatObject(args); + auto resp = client.StatObject(args); // Handle response. if (resp) { - std::cout << "Version ID: " << resp.version_id << std::endl; - std::cout << "ETag: " << resp.etag << std::endl; - std::cout << "Size: " << resp.size << std::endl; - std::cout << "Last Modified: " << resp.last_modified << std::endl; + std::cout << "Version ID: " << resp->version_id << std::endl; + std::cout << "ETag: " << resp->etag << std::endl; + std::cout << "Size: " << resp->size << std::endl; + std::cout << "Last Modified: " << resp->last_modified << std::endl; std::cout << "Retention Mode: "; - if (minio::s3::IsRetentionModeValid(resp.retention_mode)) { - std::cout << minio::s3::RetentionModeToString(resp.retention_mode) + if (minio::s3::IsRetentionModeValid(resp->retention_mode)) { + std::cout << minio::s3::RetentionModeToString(resp->retention_mode) << std::endl; } else { std::cout << "-" << std::endl; } std::cout << "Retention Retain Until Date: "; - if (resp.retention_retain_until_date) { - std::cout << resp.retention_retain_until_date.ToHttpHeaderValue() + if (resp->retention_retain_until_date) { + std::cout << resp->retention_retain_until_date.ToHttpHeaderValue() << std::endl; } else { std::cout << "-" << std::endl; } std::cout << "Legal Hold: "; - if (minio::s3::IsLegalHoldValid(resp.legal_hold)) { - std::cout << minio::s3::LegalHoldToString(resp.legal_hold) << std::endl; + if (minio::s3::IsLegalHoldValid(resp->legal_hold)) { + std::cout << minio::s3::LegalHoldToString(resp->legal_hold) << std::endl; } else { std::cout << "-" << std::endl; } std::cout << "Delete Marker: " - << minio::utils::BoolToString(resp.delete_marker) << std::endl; + << minio::utils::BoolToString(resp->delete_marker) << std::endl; std::cout << "User Metadata: " << std::endl; - std::list keys = resp.user_metadata.Keys(); + std::list keys = resp->user_metadata.Keys(); for (auto& key : keys) { - std::cout << " " << key << ": " << resp.user_metadata.GetFront(key) + std::cout << " " << key << ": " << resp->user_metadata.GetFront(key) << std::endl; } } else { - std::cout << "unable to get stat object; " << resp.Error().String() + std::cout << "unable to get stat object; " << resp.error().String() << std::endl; } diff --git a/examples/UploadObject.cc b/examples/UploadObject.cc index 629f9f0..38e375c 100644 --- a/examples/UploadObject.cc +++ b/examples/UploadObject.cc @@ -35,14 +35,14 @@ int main() { args.filename = "my-object.csv"; // Call upload object. - minio::s3::UploadObjectResponse resp = client.UploadObject(args); + auto resp = client.UploadObject(args); // Handle response. if (resp) { std::cout << "my-object.csv is successfully uploaded to my-object" << std::endl; } else { - std::cout << "unable to upload object; " << resp.Error().String() + std::cout << "unable to upload object; " << resp.error().String() << std::endl; } diff --git a/include/miniocpp/baseclient.h b/include/miniocpp/baseclient.h index 1b9c336..67feb8b 100644 --- a/include/miniocpp/baseclient.h +++ b/include/miniocpp/baseclient.h @@ -31,6 +31,7 @@ #include "providers.h" #include "request.h" #include "response.h" +#include "result.h" #include "utils.h" #ifdef MINIO_CPP_RDMA @@ -93,176 +94,201 @@ class BaseClient { const utils::Multimap& headers, const std::string& bucket_name, bool retry = false); - Response GetErrorResponse(http::Response resp, std::string_view resource, - http::Method method, const std::string& bucket_name, - const std::string& object_name); - Response execute(Request& req); - Response Execute(Request& req); - GetRegionResponse GetRegion(const std::string& bucket_name, - const std::string& region); + Result GetErrorResponse(http::Response resp, + std::string_view resource, + http::Method method, + const std::string& bucket_name, + const std::string& object_name); + Result execute(Request& req); + Result Execute(Request& req); + Result GetRegion(const std::string& bucket_name, + const std::string& region); - AbortMultipartUploadResponse AbortMultipartUpload( + Result AbortMultipartUpload( AbortMultipartUploadArgs args); - BucketExistsResponse BucketExists(BucketExistsArgs args); - CompleteMultipartUploadResponse CompleteMultipartUpload( + Result BucketExists(BucketExistsArgs args); + Result CompleteMultipartUpload( CompleteMultipartUploadArgs args); - CreateMultipartUploadResponse CreateMultipartUpload( + Result CreateMultipartUpload( CreateMultipartUploadArgs args); - DeleteBucketEncryptionResponse DeleteBucketEncryption( + Result DeleteBucketEncryption( DeleteBucketEncryptionArgs args); - DisableObjectLegalHoldResponse DisableObjectLegalHold( + Result DisableObjectLegalHold( DisableObjectLegalHoldArgs args); - DeleteBucketLifecycleResponse DeleteBucketLifecycle( + Result DeleteBucketLifecycle( DeleteBucketLifecycleArgs args); - DeleteBucketNotificationResponse DeleteBucketNotification( + Result DeleteBucketNotification( DeleteBucketNotificationArgs args); - DeleteBucketPolicyResponse DeleteBucketPolicy(DeleteBucketPolicyArgs args); - DeleteBucketReplicationResponse DeleteBucketReplication( + Result DeleteBucketPolicy( + DeleteBucketPolicyArgs args); + Result DeleteBucketReplication( DeleteBucketReplicationArgs args); - DeleteBucketTagsResponse DeleteBucketTags(DeleteBucketTagsArgs args); - DeleteObjectLockConfigResponse DeleteObjectLockConfig( + Result DeleteBucketTags(DeleteBucketTagsArgs args); + Result DeleteObjectLockConfig( DeleteObjectLockConfigArgs args); - DeleteObjectTagsResponse DeleteObjectTags(DeleteObjectTagsArgs args); - EnableObjectLegalHoldResponse EnableObjectLegalHold( + Result DeleteObjectTags(DeleteObjectTagsArgs args); + Result EnableObjectLegalHold( EnableObjectLegalHoldArgs args); - GetBucketEncryptionResponse GetBucketEncryption(GetBucketEncryptionArgs args); - GetBucketLifecycleResponse GetBucketLifecycle(GetBucketLifecycleArgs args); - GetBucketNotificationResponse GetBucketNotification( + Result GetBucketEncryption( + GetBucketEncryptionArgs args); + Result GetBucketLifecycle( + GetBucketLifecycleArgs args); + Result GetBucketNotification( GetBucketNotificationArgs args); - GetBucketPolicyResponse GetBucketPolicy(GetBucketPolicyArgs args); - GetBucketReplicationResponse GetBucketReplication( + Result GetBucketPolicy(GetBucketPolicyArgs args); + Result GetBucketReplication( GetBucketReplicationArgs args); - GetBucketTagsResponse GetBucketTags(GetBucketTagsArgs args); - GetBucketVersioningResponse GetBucketVersioning(GetBucketVersioningArgs args); - GetObjectResponse GetObject(GetObjectArgs args); - GetObjectLockConfigResponse GetObjectLockConfig(GetObjectLockConfigArgs args); - GetObjectRetentionResponse GetObjectRetention(GetObjectRetentionArgs args); - GetObjectTagsResponse GetObjectTags(GetObjectTagsArgs args); - GetPresignedObjectUrlResponse GetPresignedObjectUrl( + Result GetBucketTags(GetBucketTagsArgs args); + Result GetBucketVersioning( + GetBucketVersioningArgs args); + Result GetObject(GetObjectArgs args); + Result GetObjectLockConfig( + GetObjectLockConfigArgs args); + Result GetObjectRetention( + GetObjectRetentionArgs args); + Result GetObjectTags(GetObjectTagsArgs args); + Result GetPresignedObjectUrl( GetPresignedObjectUrlArgs args); - GetPresignedPostFormDataResponse GetPresignedPostFormData(PostPolicy policy); - IsObjectLegalHoldEnabledResponse IsObjectLegalHoldEnabled( + Result GetPresignedPostFormData( + PostPolicy policy); + Result IsObjectLegalHoldEnabled( IsObjectLegalHoldEnabledArgs args); - ListBucketsResponse ListBuckets(ListBucketsArgs args); - ListBucketsResponse ListBuckets(); - ListenBucketNotificationResponse ListenBucketNotification( + Result ListBuckets(ListBucketsArgs args); + Result ListBuckets(); + Result ListenBucketNotification( ListenBucketNotificationArgs args); - ListObjectsResponse ListObjectsV1(ListObjectsV1Args args); - ListObjectsResponse ListObjectsV2(ListObjectsV2Args args); - ListObjectsResponse ListObjectVersions(ListObjectVersionsArgs args); - MakeBucketResponse MakeBucket(MakeBucketArgs args); - PutObjectResponse PutObject(PutObjectApiArgs args); - RemoveBucketResponse RemoveBucket(RemoveBucketArgs args); - RemoveObjectResponse RemoveObject(RemoveObjectArgs args); - RemoveObjectsResponse RemoveObjects(RemoveObjectsApiArgs args); - SetBucketEncryptionResponse SetBucketEncryption(SetBucketEncryptionArgs args); - SetBucketLifecycleResponse SetBucketLifecycle(SetBucketLifecycleArgs args); - SetBucketNotificationResponse SetBucketNotification( + Result ListObjectsV1(ListObjectsV1Args args); + Result ListObjectsV2(ListObjectsV2Args args); + Result ListObjectVersions(ListObjectVersionsArgs args); + Result MakeBucket(MakeBucketArgs args); + Result PutObject(PutObjectApiArgs args); + Result RemoveBucket(RemoveBucketArgs args); + Result RemoveObject(RemoveObjectArgs args); + Result RemoveObjects(RemoveObjectsApiArgs args); + Result SetBucketEncryption( + SetBucketEncryptionArgs args); + Result SetBucketLifecycle( + SetBucketLifecycleArgs args); + Result SetBucketNotification( SetBucketNotificationArgs args); - SetBucketPolicyResponse SetBucketPolicy(SetBucketPolicyArgs args); - SetBucketReplicationResponse SetBucketReplication( + Result SetBucketPolicy(SetBucketPolicyArgs args); + Result SetBucketReplication( SetBucketReplicationArgs args); - SetBucketTagsResponse SetBucketTags(SetBucketTagsArgs args); - SetBucketVersioningResponse SetBucketVersioning(SetBucketVersioningArgs args); - SetObjectLockConfigResponse SetObjectLockConfig(SetObjectLockConfigArgs args); - SetObjectRetentionResponse SetObjectRetention(SetObjectRetentionArgs args); - SetObjectTagsResponse SetObjectTags(SetObjectTagsArgs args); - SelectObjectContentResponse SelectObjectContent(SelectObjectContentArgs args); - StatObjectResponse StatObject(StatObjectArgs args); - UploadPartResponse UploadPart(UploadPartArgs args); - UploadPartCopyResponse UploadPartCopy(UploadPartCopyArgs args); + Result SetBucketTags(SetBucketTagsArgs args); + Result SetBucketVersioning( + SetBucketVersioningArgs args); + Result SetObjectLockConfig( + SetObjectLockConfigArgs args); + Result SetObjectRetention( + SetObjectRetentionArgs args); + Result SetObjectTags(SetObjectTagsArgs args); + Result SelectObjectContent( + SelectObjectContentArgs args); + Result StatObject(StatObjectArgs args); + Result UploadPart(UploadPartArgs args); + Result UploadPartCopy(UploadPartCopyArgs args); - // Async overloads — return std::future backed by std::async. - // These are additive and non-breaking; sync methods remain unchanged. - std::future AbortMultipartUploadAsync( + // Async overloads — return std::future> backed by std::async. + // All sync methods now also return Result. + std::future> AbortMultipartUploadAsync( AbortMultipartUploadArgs args); - std::future BucketExistsAsync(BucketExistsArgs args); - std::future CompleteMultipartUploadAsync( - CompleteMultipartUploadArgs args); - std::future CreateMultipartUploadAsync( + std::future> BucketExistsAsync( + BucketExistsArgs args); + std::future> + CompleteMultipartUploadAsync(CompleteMultipartUploadArgs args); + std::future> CreateMultipartUploadAsync( CreateMultipartUploadArgs args); - std::future DeleteBucketEncryptionAsync( - DeleteBucketEncryptionArgs args); - std::future DeleteBucketLifecycleAsync( + std::future> + DeleteBucketEncryptionAsync(DeleteBucketEncryptionArgs args); + std::future> DeleteBucketLifecycleAsync( DeleteBucketLifecycleArgs args); - std::future DeleteBucketNotificationAsync( - DeleteBucketNotificationArgs args); - std::future DeleteBucketPolicyAsync( + std::future> + DeleteBucketNotificationAsync(DeleteBucketNotificationArgs args); + std::future> DeleteBucketPolicyAsync( DeleteBucketPolicyArgs args); - std::future DeleteBucketReplicationAsync( - DeleteBucketReplicationArgs args); - std::future DeleteBucketTagsAsync( + std::future> + DeleteBucketReplicationAsync(DeleteBucketReplicationArgs args); + std::future> DeleteBucketTagsAsync( DeleteBucketTagsArgs args); - std::future DeleteObjectLockConfigAsync( - DeleteObjectLockConfigArgs args); - std::future DeleteObjectTagsAsync( + std::future> + DeleteObjectLockConfigAsync(DeleteObjectLockConfigArgs args); + std::future> DeleteObjectTagsAsync( DeleteObjectTagsArgs args); - std::future DisableObjectLegalHoldAsync( - DisableObjectLegalHoldArgs args); - std::future EnableObjectLegalHoldAsync( + std::future> + DisableObjectLegalHoldAsync(DisableObjectLegalHoldArgs args); + std::future> EnableObjectLegalHoldAsync( EnableObjectLegalHoldArgs args); - std::future GetBucketEncryptionAsync( + std::future> GetBucketEncryptionAsync( GetBucketEncryptionArgs args); - std::future GetBucketLifecycleAsync( + std::future> GetBucketLifecycleAsync( GetBucketLifecycleArgs args); - std::future GetBucketNotificationAsync( + std::future> GetBucketNotificationAsync( GetBucketNotificationArgs args); - std::future GetBucketPolicyAsync( + std::future> GetBucketPolicyAsync( GetBucketPolicyArgs args); - std::future GetBucketReplicationAsync( + std::future> GetBucketReplicationAsync( GetBucketReplicationArgs args); - std::future GetBucketTagsAsync(GetBucketTagsArgs args); - std::future GetBucketVersioningAsync( + std::future> GetBucketTagsAsync( + GetBucketTagsArgs args); + std::future> GetBucketVersioningAsync( GetBucketVersioningArgs args); - std::future GetObjectAsync(GetObjectArgs args); - std::future GetObjectLockConfigAsync( + std::future> GetObjectAsync(GetObjectArgs args); + std::future> GetObjectLockConfigAsync( GetObjectLockConfigArgs args); - std::future GetObjectRetentionAsync( + std::future> GetObjectRetentionAsync( GetObjectRetentionArgs args); - std::future GetObjectTagsAsync(GetObjectTagsArgs args); - std::future GetPresignedObjectUrlAsync( + std::future> GetObjectTagsAsync( + GetObjectTagsArgs args); + std::future> GetPresignedObjectUrlAsync( GetPresignedObjectUrlArgs args); - std::future GetPresignedPostFormDataAsync( - PostPolicy policy); - std::future IsObjectLegalHoldEnabledAsync( - IsObjectLegalHoldEnabledArgs args); - std::future ListBucketsAsync(ListBucketsArgs args); - std::future ListBucketsAsync(); - std::future ListenBucketNotificationAsync( - ListenBucketNotificationArgs args); - std::future ListObjectsV1Async(ListObjectsV1Args args); - std::future ListObjectsV2Async(ListObjectsV2Args args); - std::future ListObjectVersionsAsync( + std::future> + GetPresignedPostFormDataAsync(PostPolicy policy); + std::future> + IsObjectLegalHoldEnabledAsync(IsObjectLegalHoldEnabledArgs args); + std::future> ListBucketsAsync( + ListBucketsArgs args); + std::future> ListBucketsAsync(); + std::future> + ListenBucketNotificationAsync(ListenBucketNotificationArgs args); + std::future> ListObjectsV1Async( + ListObjectsV1Args args); + std::future> ListObjectsV2Async( + ListObjectsV2Args args); + std::future> ListObjectVersionsAsync( ListObjectVersionsArgs args); - std::future MakeBucketAsync(MakeBucketArgs args); - std::future PutObjectAsync(PutObjectApiArgs args); - std::future RemoveBucketAsync(RemoveBucketArgs args); - std::future RemoveObjectAsync(RemoveObjectArgs args); - std::future RemoveObjectsAsync( + std::future> MakeBucketAsync(MakeBucketArgs args); + std::future> PutObjectAsync(PutObjectApiArgs args); + std::future> RemoveBucketAsync( + RemoveBucketArgs args); + std::future> RemoveObjectAsync( + RemoveObjectArgs args); + std::future> RemoveObjectsAsync( RemoveObjectsApiArgs args); - std::future SelectObjectContentAsync( + std::future> SelectObjectContentAsync( SelectObjectContentArgs args); - std::future SetBucketEncryptionAsync( + std::future> SetBucketEncryptionAsync( SetBucketEncryptionArgs args); - std::future SetBucketLifecycleAsync( + std::future> SetBucketLifecycleAsync( SetBucketLifecycleArgs args); - std::future SetBucketNotificationAsync( + std::future> SetBucketNotificationAsync( SetBucketNotificationArgs args); - std::future SetBucketPolicyAsync( + std::future> SetBucketPolicyAsync( SetBucketPolicyArgs args); - std::future SetBucketReplicationAsync( + std::future> SetBucketReplicationAsync( SetBucketReplicationArgs args); - std::future SetBucketTagsAsync(SetBucketTagsArgs args); - std::future SetBucketVersioningAsync( + std::future> SetBucketTagsAsync( + SetBucketTagsArgs args); + std::future> SetBucketVersioningAsync( SetBucketVersioningArgs args); - std::future SetObjectLockConfigAsync( + std::future> SetObjectLockConfigAsync( SetObjectLockConfigArgs args); - std::future SetObjectRetentionAsync( + std::future> SetObjectRetentionAsync( SetObjectRetentionArgs args); - std::future SetObjectTagsAsync(SetObjectTagsArgs args); - std::future StatObjectAsync(StatObjectArgs args); - std::future UploadPartAsync(UploadPartArgs args); - std::future UploadPartCopyAsync( + std::future> SetObjectTagsAsync( + SetObjectTagsArgs args); + std::future> StatObjectAsync(StatObjectArgs args); + std::future> UploadPartAsync(UploadPartArgs args); + std::future> UploadPartCopyAsync( UploadPartCopyArgs args); // Windows API fix: @@ -273,11 +299,11 @@ class BaseClient { // didn't. This fixes the issue by providing both functions `GetObject()` can // expand to as inline wrappers. #if defined(_WIN32) - inline GetObjectResponse GetObjectA(const GetObjectArgs& args) { + inline Result GetObjectA(const GetObjectArgs& args) { return GetObject(args); } - inline GetObjectResponse GetObjectW(const GetObjectArgs& args) { + inline Result GetObjectW(const GetObjectArgs& args) { return GetObject(args); } #endif // _WIN32 diff --git a/include/miniocpp/client.h b/include/miniocpp/client.h index e493903..55f5353 100644 --- a/include/miniocpp/client.h +++ b/include/miniocpp/client.h @@ -28,6 +28,7 @@ #include "providers.h" #include "request.h" #include "response.h" +#include "result.h" namespace minio::s3 { @@ -117,12 +118,12 @@ class RemoveObjectsResult { */ class Client : public BaseClient { protected: - StatObjectResponse CalculatePartCount(size_t& part_count, - std::list sources); - ComposeObjectResponse ComposeObject(ComposeObjectArgs args, - std::string& upload_id); - PutObjectResponse PutObject(PutObjectArgs args, std::string& upload_id, - char* buf); + Result CalculatePartCount( + size_t& part_count, std::list sources); + Result ComposeObject(ComposeObjectArgs args, + std::string& upload_id); + Result PutObject(PutObjectArgs args, + std::string& upload_id, char* buf); #ifdef MINIO_CPP_RDMA // Process-wide RDMA client, one instance for the whole process, lazily @@ -143,13 +144,13 @@ class Client : public BaseClient { explicit Client(BaseUrl& base_url, creds::Provider* const provider = nullptr); ~Client() = default; - ComposeObjectResponse ComposeObject(ComposeObjectArgs args); - CopyObjectResponse CopyObject(CopyObjectArgs args); - DownloadObjectResponse DownloadObject(DownloadObjectArgs args); + Result ComposeObject(ComposeObjectArgs args); + Result CopyObject(CopyObjectArgs args); + Result DownloadObject(DownloadObjectArgs args); ListObjectsResult ListObjects(ListObjectsArgs args); - PutObjectResponse PutObject(PutObjectArgs args); - GetObjectResponse GetObject(GetObjectArgs args); - UploadObjectResponse UploadObject(UploadObjectArgs args); + Result PutObject(PutObjectArgs args); + Result GetObject(GetObjectArgs args); + Result UploadObject(UploadObjectArgs args); RemoveObjectsResult RemoveObjects(RemoveObjectsArgs args); // Async overloads — return std::future backed by std::async. @@ -157,14 +158,16 @@ class Client : public BaseClient { // Lifetime note for PutObjectAsync: the caller must ensure // args.stream (if set) outlives the returned std::future, // exactly as it must for the synchronous PutObject call. - std::future ComposeObjectAsync(ComposeObjectArgs args); - std::future CopyObjectAsync(CopyObjectArgs args); - std::future DownloadObjectAsync( + std::future> ComposeObjectAsync( + ComposeObjectArgs args); + std::future> CopyObjectAsync(CopyObjectArgs args); + std::future> DownloadObjectAsync( DownloadObjectArgs args); - std::future GetObjectAsync(GetObjectArgs args); + std::future> GetObjectAsync(GetObjectArgs args); std::future ListObjectsAsync(ListObjectsArgs args); - std::future PutObjectAsync(PutObjectArgs args); - std::future UploadObjectAsync(UploadObjectArgs args); + std::future> PutObjectAsync(PutObjectArgs args); + std::future> UploadObjectAsync( + UploadObjectArgs args); }; // class Client } // namespace minio::s3 diff --git a/include/miniocpp/credentials.h b/include/miniocpp/credentials.h index 9c68e8d..7fb2cc5 100644 --- a/include/miniocpp/credentials.h +++ b/include/miniocpp/credentials.h @@ -22,6 +22,7 @@ #include #include "error.h" +#include "result.h" #include "utils.h" namespace minio::creds { @@ -72,7 +73,8 @@ struct Credentials { return !err && !access_key.empty() && !expired(expiration); } - static Credentials ParseXML(std::string_view data, const std::string& root); + static Result ParseXML(std::string_view data, + const std::string& root); }; // class Credentials } // namespace minio::creds diff --git a/include/miniocpp/error.h b/include/miniocpp/error.h index f90a473..9d9a716 100644 --- a/include/miniocpp/error.h +++ b/include/miniocpp/error.h @@ -22,6 +22,8 @@ #include #include +#include "tl/expected.hpp" + namespace minio::error { class Error { @@ -52,8 +54,8 @@ class Error { extern const Error SUCCESS; template -inline T_RESULT make(TA&&... args) { - return T_RESULT{Error(std::forward(args)...)}; +inline tl::expected make(TA&&... args) { + return tl::make_unexpected(Error(std::forward(args)...)); } } // namespace minio::error diff --git a/include/miniocpp/response.h b/include/miniocpp/response.h index 44ade87..aa56c30 100644 --- a/include/miniocpp/response.h +++ b/include/miniocpp/response.h @@ -27,6 +27,7 @@ #include #include "error.h" +#include "result.h" #include "types.h" #include "utils.h" @@ -47,12 +48,7 @@ struct Response { std::string object_name; std::string etag; - private: - error::Error err_; - - public: Response(); - explicit Response(error::Error err) : err_(std::move(err)) {} Response(const Response& resp) = default; Response& operator=(const Response& resp) = default; @@ -62,30 +58,22 @@ struct Response { ~Response(); - explicit operator bool() const { - return !err_ && code.empty() && message.empty() && - (status_code == 0 || (status_code >= 200 && status_code <= 299)); - } - - error::Error Error() const; - - static Response ParseXML(std::string_view data, int status_code, - utils::Multimap headers); + static Result ParseXML(std::string_view data, int status_code, + utils::Multimap headers); }; // struct Response -#define MINIO_S3_DERIVE_FROM_RESPONSE(DerivedName) \ - struct DerivedName : public Response { \ - DerivedName() = default; \ - ~DerivedName() = default; \ - \ - DerivedName(const DerivedName&) = default; \ - DerivedName& operator=(const DerivedName&) = default; \ - \ - DerivedName(DerivedName&&) = default; \ - DerivedName& operator=(DerivedName&&) = default; \ - \ - explicit DerivedName(error::Error err) : Response(std::move(err)) {} \ - explicit DerivedName(const Response& resp) : Response(resp) {} \ +#define MINIO_S3_DERIVE_FROM_RESPONSE(DerivedName) \ + struct DerivedName : public Response { \ + DerivedName() = default; \ + ~DerivedName() = default; \ + \ + DerivedName(const DerivedName&) = default; \ + DerivedName& operator=(const DerivedName&) = default; \ + \ + DerivedName(DerivedName&&) = default; \ + DerivedName& operator=(DerivedName&&) = default; \ + \ + explicit DerivedName(const Response& resp) : Response(resp) {} \ }; #define MINIO_S3_DERIVE_FROM_PUT_OBJECT_RESPONSE(DerivedName) \ @@ -99,8 +87,6 @@ struct Response { DerivedName(DerivedName&&) = default; \ DerivedName& operator=(DerivedName&&) = default; \ \ - explicit DerivedName(error::Error err) \ - : PutObjectResponse(std::move(err)) {} \ explicit DerivedName(const PutObjectResponse& resp) \ : PutObjectResponse(resp) {} \ explicit DerivedName(const Response& resp) : PutObjectResponse(resp) {} \ @@ -114,8 +100,6 @@ struct GetRegionResponse : public Response { explicit GetRegionResponse(std::string region) : region(std::move(region)) {} - explicit GetRegionResponse(error::Error err) : Response(std::move(err)) {} - explicit GetRegionResponse(const Response& resp) : Response(resp) {} ~GetRegionResponse() = default; @@ -129,13 +113,11 @@ struct ListBucketsResponse : public Response { explicit ListBucketsResponse(std::list buckets) : buckets(std::move(buckets)) {} - explicit ListBucketsResponse(error::Error err) : Response(std::move(err)) {} - explicit ListBucketsResponse(const Response& resp) : Response(resp) {} ~ListBucketsResponse() = default; - static ListBucketsResponse ParseXML(std::string_view data); + static Result ParseXML(std::string_view data); }; // struct ListBucketsResponse struct BucketExistsResponse : public Response { @@ -143,8 +125,6 @@ struct BucketExistsResponse : public Response { explicit BucketExistsResponse(bool exist) : exist(exist) {} - explicit BucketExistsResponse(error::Error err) : Response(std::move(err)) {} - explicit BucketExistsResponse(const Response& resp) : Response(resp) {} ~BucketExistsResponse() = default; @@ -165,16 +145,13 @@ struct CompleteMultipartUploadResponse : public Response { CompleteMultipartUploadResponse() = default; - explicit CompleteMultipartUploadResponse(error::Error err) - : Response(std::move(err)) {} - explicit CompleteMultipartUploadResponse(const Response& resp) : Response(resp) {} ~CompleteMultipartUploadResponse() = default; - static CompleteMultipartUploadResponse ParseXML(std::string_view data, - std::string version_id); + static Result ParseXML( + std::string_view data, std::string version_id); }; // struct CompleteMultipartUploadResponse struct CreateMultipartUploadResponse : public Response { @@ -183,9 +160,6 @@ struct CreateMultipartUploadResponse : public Response { explicit CreateMultipartUploadResponse(std::string upload_id) : upload_id(std::move(upload_id)) {} - explicit CreateMultipartUploadResponse(error::Error err) - : Response(std::move(err)) {} - explicit CreateMultipartUploadResponse(const Response& resp) : Response(resp) {} @@ -203,8 +177,6 @@ struct PutObjectResponse : public Response { PutObjectResponse() = default; - explicit PutObjectResponse(error::Error err) : Response(std::move(err)) {} - explicit PutObjectResponse(const Response& resp) : Response(resp) {} explicit PutObjectResponse(const CompleteMultipartUploadResponse& resp) @@ -229,8 +201,6 @@ struct StatObjectResponse : public Response { StatObjectResponse() = default; - explicit StatObjectResponse(error::Error err) : Response(std::move(err)) {} - explicit StatObjectResponse(const Response& resp) : Response(resp) {} ~StatObjectResponse() = default; @@ -259,8 +229,6 @@ struct Item : public Response { Item() = default; - explicit Item(error::Error err) : Response(std::move(err)) {} - explicit Item(const Response& resp) : Response(resp) {} ~Item() = default; @@ -303,11 +271,10 @@ struct ListObjectsResponse : public Response { ListObjectsResponse(ListObjectsResponse&&) = default; ListObjectsResponse& operator=(ListObjectsResponse&&) = default; - explicit ListObjectsResponse(error::Error err) : Response(std::move(err)) {} - explicit ListObjectsResponse(const Response& resp) : Response(resp) {} - static ListObjectsResponse ParseXML(std::string_view data, bool version); + static Result ParseXML(std::string_view data, + bool version); }; // struct ListObjectsResponse MINIO_S3_DERIVE_FROM_PUT_OBJECT_RESPONSE(CopyObjectResponse) @@ -329,8 +296,6 @@ struct DeleteError : public Response { DeleteError() = default; - explicit DeleteError(error::Error err) : Response(std::move(err)) {} - explicit DeleteError(const Response& resp) : Response(resp) {} ~DeleteError() = default; @@ -342,13 +307,11 @@ struct RemoveObjectsResponse : public Response { RemoveObjectsResponse() = default; - explicit RemoveObjectsResponse(error::Error err) : Response(std::move(err)) {} - explicit RemoveObjectsResponse(const Response& resp) : Response(resp) {} ~RemoveObjectsResponse() = default; - static RemoveObjectsResponse ParseXML(std::string_view data); + static Result ParseXML(std::string_view data); }; // struct RemoveObjectsResponse MINIO_S3_DERIVE_FROM_RESPONSE(SelectObjectContentResponse) @@ -361,9 +324,6 @@ struct GetBucketPolicyResponse : public Response { explicit GetBucketPolicyResponse(std::string policy) : policy(std::move(policy)) {} - explicit GetBucketPolicyResponse(error::Error err) - : Response(std::move(err)) {} - explicit GetBucketPolicyResponse(const Response& resp) : Response(resp) {} ~GetBucketPolicyResponse() = default; @@ -378,15 +338,12 @@ struct GetBucketNotificationResponse : public Response { explicit GetBucketNotificationResponse(NotificationConfig config) : config(std::move(config)) {} - explicit GetBucketNotificationResponse(error::Error err) - : Response(std::move(err)) {} - explicit GetBucketNotificationResponse(const Response& resp) : Response(resp) {} ~GetBucketNotificationResponse() = default; - static GetBucketNotificationResponse ParseXML(std::string_view data); + static Result ParseXML(std::string_view data); }; // struct GetBucketNotificationResponse MINIO_S3_DERIVE_FROM_RESPONSE(SetBucketNotificationResponse) @@ -398,14 +355,11 @@ struct GetBucketEncryptionResponse : public Response { explicit GetBucketEncryptionResponse(SseConfig config) : config(std::move(config)) {} - explicit GetBucketEncryptionResponse(error::Error err) - : Response(std::move(err)) {} - explicit GetBucketEncryptionResponse(const Response& resp) : Response(resp) {} ~GetBucketEncryptionResponse() = default; - static GetBucketEncryptionResponse ParseXML(std::string_view data); + static Result ParseXML(std::string_view data); }; // struct GetBucketEncryptionResponse MINIO_S3_DERIVE_FROM_RESPONSE(SetBucketEncryptionResponse) @@ -416,9 +370,6 @@ struct GetBucketVersioningResponse : public Response { GetBucketVersioningResponse() = default; - explicit GetBucketVersioningResponse(error::Error err) - : Response(std::move(err)) {} - explicit GetBucketVersioningResponse(const Response& resp) : Response(resp) {} ~GetBucketVersioningResponse() = default; @@ -445,15 +396,12 @@ struct GetBucketReplicationResponse : public Response { explicit GetBucketReplicationResponse(ReplicationConfig config) : config(std::move(config)) {} - explicit GetBucketReplicationResponse(error::Error err) - : Response(std::move(err)) {} - explicit GetBucketReplicationResponse(const Response& resp) : Response(resp) {} ~GetBucketReplicationResponse() = default; - static GetBucketReplicationResponse ParseXML(std::string_view data); + static Result ParseXML(std::string_view data); }; // struct GetBucketReplicationResponse MINIO_S3_DERIVE_FROM_RESPONSE(SetBucketReplicationResponse) @@ -465,12 +413,9 @@ struct GetBucketLifecycleResponse : public Response { explicit GetBucketLifecycleResponse(LifecycleConfig config) : config(std::move(config)) {} - explicit GetBucketLifecycleResponse(error::Error err) - : Response(std::move(err)) {} - explicit GetBucketLifecycleResponse(const Response& resp) : Response(resp) {} - static GetBucketLifecycleResponse ParseXML(std::string_view data); + static Result ParseXML(std::string_view data); }; // struct GetBucketLifecycleResponse MINIO_S3_DERIVE_FROM_RESPONSE(SetBucketLifecycleResponse) @@ -482,13 +427,11 @@ struct GetBucketTagsResponse : public Response { GetBucketTagsResponse(std::map tags) : tags(std::move(tags)) {} - explicit GetBucketTagsResponse(error::Error err) : Response(std::move(err)) {} - explicit GetBucketTagsResponse(const Response& resp) : Response(resp) {} ~GetBucketTagsResponse() = default; - static GetBucketTagsResponse ParseXML(std::string_view data); + static Result ParseXML(std::string_view data); }; // struct GetBucketTagsResponse MINIO_S3_DERIVE_FROM_RESPONSE(SetBucketTagsResponse) @@ -500,9 +443,6 @@ struct GetObjectLockConfigResponse : public Response { explicit GetObjectLockConfigResponse(ObjectLockConfig config) : config(std::move(config)) {} - explicit GetObjectLockConfigResponse(error::Error err) - : Response(std::move(err)) {} - explicit GetObjectLockConfigResponse(const Response& resp) : Response(resp) {} ~GetObjectLockConfigResponse() = default; @@ -517,13 +457,11 @@ struct GetObjectTagsResponse : public Response { GetObjectTagsResponse(std::map tags) : tags(std::move(tags)) {} - explicit GetObjectTagsResponse(error::Error err) : Response(std::move(err)) {} - explicit GetObjectTagsResponse(const Response& resp) : Response(resp) {} ~GetObjectTagsResponse() = default; - static GetObjectTagsResponse ParseXML(std::string_view data); + static Result ParseXML(std::string_view data); }; // struct GetObjectTagsResponse MINIO_S3_DERIVE_FROM_RESPONSE(SetObjectTagsResponse) @@ -535,9 +473,6 @@ struct IsObjectLegalHoldEnabledResponse : public Response { explicit IsObjectLegalHoldEnabledResponse(bool enabled) : enabled(enabled) {} - explicit IsObjectLegalHoldEnabledResponse(error::Error err) - : Response(std::move(err)) {} - explicit IsObjectLegalHoldEnabledResponse(const Response& resp) : Response(resp) {} @@ -550,9 +485,6 @@ struct GetObjectRetentionResponse : public Response { GetObjectRetentionResponse() = default; - explicit GetObjectRetentionResponse(error::Error err) - : Response(std::move(err)) {} - explicit GetObjectRetentionResponse(const Response& resp) : Response(resp) {} ~GetObjectRetentionResponse() = default; @@ -566,9 +498,6 @@ struct GetPresignedObjectUrlResponse : public Response { explicit GetPresignedObjectUrlResponse(std::string url) : url(std::move(url)) {} - explicit GetPresignedObjectUrlResponse(error::Error err) - : Response(std::move(err)) {} - explicit GetPresignedObjectUrlResponse(const Response& resp) : Response(resp) {} @@ -581,9 +510,6 @@ struct GetPresignedPostFormDataResponse : public Response { GetPresignedPostFormDataResponse(std::map form_data) : form_data(std::move(form_data)) {} - explicit GetPresignedPostFormDataResponse(error::Error err) - : Response(std::move(err)) {} - explicit GetPresignedPostFormDataResponse(const Response& resp) : Response(resp) {} diff --git a/include/miniocpp/result.h b/include/miniocpp/result.h new file mode 100644 index 0000000..af9b2ea --- /dev/null +++ b/include/miniocpp/result.h @@ -0,0 +1,31 @@ +// MinIO C++ Library for Amazon S3 Compatible Cloud Storage +// Copyright 2022-2024 MinIO, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// SPDX-License-Identifier: Apache-2.0 + +#ifndef MINIO_CPP_RESULT_H_INCLUDED +#define MINIO_CPP_RESULT_H_INCLUDED + +#include "error.h" +#include "tl/expected.hpp" + +namespace minio { + +template +using Result = tl::expected; + +} // namespace minio + +#endif // MINIO_CPP_RESULT_H_INCLUDED diff --git a/include/tl/expected.hpp b/include/tl/expected.hpp new file mode 100644 index 0000000..59e59aa --- /dev/null +++ b/include/tl/expected.hpp @@ -0,0 +1,2475 @@ +/// +// expected - An implementation of std::expected with extensions +// Written in 2017 by Sy Brand (tartanllama@gmail.com, @TartanLlama) +// +// Documentation available at http://tl.tartanllama.xyz/ +// +// To the extent possible under law, the author(s) have dedicated all +// copyright and related and neighboring rights to this software to the +// public domain worldwide. This software is distributed without any warranty. +// +// You should have received a copy of the CC0 Public Domain Dedication +// along with this software. If not, see +// . +/// + +#ifndef TL_EXPECTED_HPP +#define TL_EXPECTED_HPP + +#define TL_EXPECTED_VERSION_MAJOR 1 +#define TL_EXPECTED_VERSION_MINOR 3 +#define TL_EXPECTED_VERSION_PATCH 1 + +#include +#include +#include +#include + +#if defined(__EXCEPTIONS) || defined(_CPPUNWIND) +#define TL_EXPECTED_EXCEPTIONS_ENABLED +#endif + +#if (defined(_MSC_VER) && _MSC_VER == 1900) +#define TL_EXPECTED_MSVC2015 +#define TL_EXPECTED_MSVC2015_CONSTEXPR +#else +#define TL_EXPECTED_MSVC2015_CONSTEXPR constexpr +#endif + +#if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && \ + !defined(__clang__)) +#define TL_EXPECTED_GCC49 +#endif + +#if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 4 && \ + !defined(__clang__)) +#define TL_EXPECTED_GCC54 +#endif + +#if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 5 && \ + !defined(__clang__)) +#define TL_EXPECTED_GCC55 +#endif + +#ifdef _MSVC_LANG +#define TL_CPLUSPLUS _MSVC_LANG +#else +#define TL_CPLUSPLUS __cplusplus +#endif + +#if !defined(TL_ASSERT) +//can't have assert in constexpr in C++11 and GCC 4.9 has a compiler bug +#if (TL_CPLUSPLUS > 201103L) && !defined(TL_EXPECTED_GCC49) +#include +#define TL_ASSERT(x) assert(x) +#else +#define TL_ASSERT(x) +#endif +#endif + +#if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && \ + !defined(__clang__)) +// GCC < 5 doesn't support overloading on const&& for member functions + +#define TL_EXPECTED_NO_CONSTRR +// GCC < 5 doesn't support some standard C++11 type traits +#define TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \ + std::has_trivial_copy_constructor +#define TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \ + std::has_trivial_copy_assign + +// This one will be different for GCC 5.7 if it's ever supported +#define TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T) \ + std::is_trivially_destructible + +// GCC 5 < v < 8 has a bug in is_trivially_copy_constructible which breaks +// std::vector for non-copyable types +#elif (defined(__GNUC__) && __GNUC__ < 8 && !defined(__clang__)) +#ifndef TL_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX +#define TL_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX +namespace tl { +namespace detail { +template +struct is_trivially_copy_constructible + : std::is_trivially_copy_constructible {}; +#ifdef _GLIBCXX_VECTOR +template +struct is_trivially_copy_constructible> : std::false_type {}; +#endif +} // namespace detail +} // namespace tl +#endif + +#define TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \ + tl::detail::is_trivially_copy_constructible +#define TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \ + std::is_trivially_copy_assignable +#define TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T) \ + std::is_trivially_destructible +#else +#define TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \ + std::is_trivially_copy_constructible +#define TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \ + std::is_trivially_copy_assignable +#define TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T) \ + std::is_trivially_destructible +#endif + +#if TL_CPLUSPLUS > 201103L +#define TL_EXPECTED_CXX14 +#endif + +#ifdef TL_EXPECTED_GCC49 +#define TL_EXPECTED_GCC49_CONSTEXPR +#else +#define TL_EXPECTED_GCC49_CONSTEXPR constexpr +#endif + +#if (TL_CPLUSPLUS == 201103L || defined(TL_EXPECTED_MSVC2015) || \ + defined(TL_EXPECTED_GCC49)) +#define TL_EXPECTED_11_CONSTEXPR +#else +#define TL_EXPECTED_11_CONSTEXPR constexpr +#endif + +#if TL_CPLUSPLUS >= 201703L +#define TL_EXPECTED_NODISCARD [[nodiscard]] +#else +#define TL_EXPECTED_NODISCARD +#endif + +namespace tl { +template class TL_EXPECTED_NODISCARD expected; + +#ifndef TL_MONOSTATE_INPLACE_MUTEX +#define TL_MONOSTATE_INPLACE_MUTEX +class monostate {}; + +struct in_place_t { + explicit in_place_t() = default; +}; +static constexpr in_place_t in_place{}; +#endif + +template class unexpected { +public: + static_assert(!std::is_same::value, "E must not be void"); + + unexpected() = delete; + constexpr explicit unexpected(const E &e) : m_val(e) {} + + constexpr explicit unexpected(E &&e) : m_val(std::move(e)) {} + + template ::value>::type * = nullptr> + constexpr explicit unexpected(Args &&...args) + : m_val(std::forward(args)...) {} + template < + class U, class... Args, + typename std::enable_if &, Args &&...>::value>::type * = nullptr> + constexpr explicit unexpected(std::initializer_list l, Args &&...args) + : m_val(l, std::forward(args)...) {} + + constexpr const E &value() const & { return m_val; } + TL_EXPECTED_11_CONSTEXPR E &value() & { return m_val; } + TL_EXPECTED_11_CONSTEXPR E &&value() && { return std::move(m_val); } + constexpr const E &&value() const && { return std::move(m_val); } + +private: + E m_val; +}; + +#ifdef __cpp_deduction_guides +template unexpected(E) -> unexpected; +#endif + +template +constexpr bool operator==(const unexpected &lhs, const unexpected &rhs) { + return lhs.value() == rhs.value(); +} +template +constexpr bool operator!=(const unexpected &lhs, const unexpected &rhs) { + return lhs.value() != rhs.value(); +} +template +constexpr bool operator<(const unexpected &lhs, const unexpected &rhs) { + return lhs.value() < rhs.value(); +} +template +constexpr bool operator<=(const unexpected &lhs, const unexpected &rhs) { + return lhs.value() <= rhs.value(); +} +template +constexpr bool operator>(const unexpected &lhs, const unexpected &rhs) { + return lhs.value() > rhs.value(); +} +template +constexpr bool operator>=(const unexpected &lhs, const unexpected &rhs) { + return lhs.value() >= rhs.value(); +} + +template +unexpected::type> make_unexpected(E &&e) { + return unexpected::type>(std::forward(e)); +} + +struct unexpect_t { + unexpect_t() = default; +}; +static constexpr unexpect_t unexpect{}; + +#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED +#define TL_EXPECTED_THROW_EXCEPTION(e) throw((e)); +#else +#define TL_EXPECTED_THROW_EXCEPTION(e) std::terminate(); +#endif + +namespace detail { +#ifndef TL_TRAITS_MUTEX +#define TL_TRAITS_MUTEX +// C++14-style aliases for brevity +template using remove_const_t = typename std::remove_const::type; +template +using remove_reference_t = typename std::remove_reference::type; +template using decay_t = typename std::decay::type; +template +using enable_if_t = typename std::enable_if::type; +template +using conditional_t = typename std::conditional::type; + +// std::conjunction from C++17 +template struct conjunction : std::true_type {}; +template struct conjunction : B {}; +template +struct conjunction + : std::conditional, B>::type {}; + +#if defined(_LIBCPP_VERSION) && __cplusplus == 201103L +#define TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND +#endif + +// In C++11 mode, there's an issue in libc++'s std::mem_fn +// which results in a hard-error when using it in a noexcept expression +// in some cases. This is a check to workaround the common failing case. +#ifdef TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND +template +struct is_pointer_to_non_const_member_func : std::false_type {}; +template +struct is_pointer_to_non_const_member_func + : std::true_type {}; +template +struct is_pointer_to_non_const_member_func + : std::true_type {}; +template +struct is_pointer_to_non_const_member_func + : std::true_type {}; +template +struct is_pointer_to_non_const_member_func + : std::true_type {}; +template +struct is_pointer_to_non_const_member_func + : std::true_type {}; +template +struct is_pointer_to_non_const_member_func + : std::true_type {}; + +template struct is_const_or_const_ref : std::false_type {}; +template struct is_const_or_const_ref : std::true_type {}; +template struct is_const_or_const_ref : std::true_type {}; +#endif + +// std::invoke from C++17 +// https://stackoverflow.com/questions/38288042/c11-14-invoke-workaround +template < + typename Fn, typename... Args, +#ifdef TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND + typename = enable_if_t::value && + is_const_or_const_ref::value)>, +#endif + typename = enable_if_t>::value>, int = 0> +constexpr auto invoke(Fn &&f, Args &&...args) noexcept( + noexcept(std::mem_fn(f)(std::forward(args)...))) + -> decltype(std::mem_fn(f)(std::forward(args)...)) { + return std::mem_fn(f)(std::forward(args)...); +} + +template >::value>> +constexpr auto invoke(Fn &&f, Args &&...args) noexcept( + noexcept(std::forward(f)(std::forward(args)...))) + -> decltype(std::forward(f)(std::forward(args)...)) { + return std::forward(f)(std::forward(args)...); +} + +// std::invoke_result from C++17 +template struct invoke_result_impl; + +template +struct invoke_result_impl< + F, + decltype(detail::invoke(std::declval(), std::declval()...), void()), + Us...> { + using type = + decltype(detail::invoke(std::declval(), std::declval()...)); +}; + +template +using invoke_result = invoke_result_impl; + +template +using invoke_result_t = typename invoke_result::type; + +#if defined(_MSC_VER) && _MSC_VER <= 1900 +// TODO make a version which works with MSVC 2015 +template struct is_swappable : std::true_type {}; + +template struct is_nothrow_swappable : std::true_type {}; +#else +// https://stackoverflow.com/questions/26744589/what-is-a-proper-way-to-implement-is-swappable-to-test-for-the-swappable-concept +namespace swap_adl_tests { +// if swap ADL finds this then it would call std::swap otherwise (same +// signature) +struct tag {}; + +template tag swap(T &, T &); +template tag swap(T (&a)[N], T (&b)[N]); + +// helper functions to test if an unqualified swap is possible, and if it +// becomes std::swap +template std::false_type can_swap(...) noexcept(false); +template (), std::declval()))> +std::true_type can_swap(int) noexcept(noexcept(swap(std::declval(), + std::declval()))); + +template std::false_type uses_std(...); +template +std::is_same(), std::declval())), tag> +uses_std(int); + +template +struct is_std_swap_noexcept + : std::integral_constant::value && + std::is_nothrow_move_assignable::value> {}; + +template +struct is_std_swap_noexcept : is_std_swap_noexcept {}; + +template +struct is_adl_swap_noexcept + : std::integral_constant(0))> {}; +} // namespace swap_adl_tests + +template +struct is_swappable + : std::integral_constant< + bool, + decltype(detail::swap_adl_tests::can_swap(0))::value && + (!decltype(detail::swap_adl_tests::uses_std(0))::value || + (std::is_move_assignable::value && + std::is_move_constructible::value))> {}; + +template +struct is_swappable + : std::integral_constant< + bool, + decltype(detail::swap_adl_tests::can_swap(0))::value && + (!decltype(detail::swap_adl_tests::uses_std( + 0))::value || + is_swappable::value)> {}; + +template +struct is_nothrow_swappable + : std::integral_constant< + bool, + is_swappable::value && + ((decltype(detail::swap_adl_tests::uses_std(0))::value && + detail::swap_adl_tests::is_std_swap_noexcept::value) || + (!decltype(detail::swap_adl_tests::uses_std(0))::value && + detail::swap_adl_tests::is_adl_swap_noexcept::value))> {}; +#endif +#endif + +// Trait for checking if a type is a tl::expected +template struct is_expected_impl : std::false_type {}; +template +struct is_expected_impl> : std::true_type {}; +template using is_expected = is_expected_impl>; + +template +using expected_enable_forward_value = detail::enable_if_t< + std::is_constructible::value && + !std::is_same, in_place_t>::value && + !std::is_same, detail::decay_t>::value && + !std::is_same, detail::decay_t>::value>; + +template +using expected_enable_from_other = detail::enable_if_t< + std::is_constructible::value && + std::is_constructible::value && + !std::is_constructible &>::value && + !std::is_constructible &&>::value && + !std::is_constructible &>::value && + !std::is_constructible &&>::value && + !std::is_convertible &, T>::value && + !std::is_convertible &&, T>::value && + !std::is_convertible &, T>::value && + !std::is_convertible &&, T>::value>; + +template +using is_void_or = conditional_t::value, std::true_type, U>; + +template +using is_copy_constructible_or_void = + is_void_or>; + +template +using is_move_constructible_or_void = + is_void_or>; + +template +using is_copy_assignable_or_void = is_void_or>; + +template +using is_move_assignable_or_void = is_void_or>; + +} // namespace detail + +namespace detail { +struct no_init_t {}; +static constexpr no_init_t no_init{}; + +// Implements the storage of the values, and ensures that the destructor is +// trivial if it can be. +// +// This specialization is for where neither `T` or `E` is trivially +// destructible, so the destructors must be called on destruction of the +// `expected` +template ::value, + bool = std::is_trivially_destructible::value> +struct expected_storage_base { + constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {} + constexpr expected_storage_base(no_init_t) : m_no_init(), m_has_val(false) {} + + template ::value> * = + nullptr> + constexpr expected_storage_base(in_place_t, Args &&...args) + : m_val(std::forward(args)...), m_has_val(true) {} + + template &, Args &&...>::value> * = nullptr> + constexpr expected_storage_base(in_place_t, std::initializer_list il, + Args &&...args) + : m_val(il, std::forward(args)...), m_has_val(true) {} + template ::value> * = + nullptr> + constexpr explicit expected_storage_base(unexpect_t, Args &&...args) + : m_unexpect(std::forward(args)...), m_has_val(false) {} + + template &, Args &&...>::value> * = nullptr> + constexpr explicit expected_storage_base(unexpect_t, + std::initializer_list il, + Args &&...args) + : m_unexpect(il, std::forward(args)...), m_has_val(false) {} + + ~expected_storage_base() { + if (m_has_val) { + m_val.~T(); + } else { + m_unexpect.~unexpected(); + } + } + union { + T m_val; + unexpected m_unexpect; + char m_no_init; + }; + bool m_has_val; +}; + +// This specialization is for when both `T` and `E` are trivially-destructible, +// so the destructor of the `expected` can be trivial. +template struct expected_storage_base { + constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {} + constexpr expected_storage_base(no_init_t) : m_no_init(), m_has_val(false) {} + + template ::value> * = + nullptr> + constexpr expected_storage_base(in_place_t, Args &&...args) + : m_val(std::forward(args)...), m_has_val(true) {} + + template &, Args &&...>::value> * = nullptr> + constexpr expected_storage_base(in_place_t, std::initializer_list il, + Args &&...args) + : m_val(il, std::forward(args)...), m_has_val(true) {} + template ::value> * = + nullptr> + constexpr explicit expected_storage_base(unexpect_t, Args &&...args) + : m_unexpect(std::forward(args)...), m_has_val(false) {} + + template &, Args &&...>::value> * = nullptr> + constexpr explicit expected_storage_base(unexpect_t, + std::initializer_list il, + Args &&...args) + : m_unexpect(il, std::forward(args)...), m_has_val(false) {} + + expected_storage_base(const expected_storage_base &) = default; + expected_storage_base(expected_storage_base &&) = default; + expected_storage_base &operator=(const expected_storage_base &) = default; + expected_storage_base &operator=(expected_storage_base &&) = default; + ~expected_storage_base() = default; + union { + T m_val; + unexpected m_unexpect; + char m_no_init; + }; + bool m_has_val; +}; + +// T is trivial, E is not. +template struct expected_storage_base { + constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {} + TL_EXPECTED_MSVC2015_CONSTEXPR expected_storage_base(no_init_t) + : m_no_init(), m_has_val(false) {} + + template ::value> * = + nullptr> + constexpr expected_storage_base(in_place_t, Args &&...args) + : m_val(std::forward(args)...), m_has_val(true) {} + + template &, Args &&...>::value> * = nullptr> + constexpr expected_storage_base(in_place_t, std::initializer_list il, + Args &&...args) + : m_val(il, std::forward(args)...), m_has_val(true) {} + template ::value> * = + nullptr> + constexpr explicit expected_storage_base(unexpect_t, Args &&...args) + : m_unexpect(std::forward(args)...), m_has_val(false) {} + + template &, Args &&...>::value> * = nullptr> + constexpr explicit expected_storage_base(unexpect_t, + std::initializer_list il, + Args &&...args) + : m_unexpect(il, std::forward(args)...), m_has_val(false) {} + + expected_storage_base(const expected_storage_base &) = default; + expected_storage_base(expected_storage_base &&) = default; + expected_storage_base &operator=(const expected_storage_base &) = default; + expected_storage_base &operator=(expected_storage_base &&) = default; + ~expected_storage_base() { + if (!m_has_val) { + m_unexpect.~unexpected(); + } + } + + union { + T m_val; + unexpected m_unexpect; + char m_no_init; + }; + bool m_has_val; +}; + +// E is trivial, T is not. +template struct expected_storage_base { + constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {} + constexpr expected_storage_base(no_init_t) : m_no_init(), m_has_val(false) {} + + template ::value> * = + nullptr> + constexpr expected_storage_base(in_place_t, Args &&...args) + : m_val(std::forward(args)...), m_has_val(true) {} + + template &, Args &&...>::value> * = nullptr> + constexpr expected_storage_base(in_place_t, std::initializer_list il, + Args &&...args) + : m_val(il, std::forward(args)...), m_has_val(true) {} + template ::value> * = + nullptr> + constexpr explicit expected_storage_base(unexpect_t, Args &&...args) + : m_unexpect(std::forward(args)...), m_has_val(false) {} + + template &, Args &&...>::value> * = nullptr> + constexpr explicit expected_storage_base(unexpect_t, + std::initializer_list il, + Args &&...args) + : m_unexpect(il, std::forward(args)...), m_has_val(false) {} + + expected_storage_base(const expected_storage_base &) = default; + expected_storage_base(expected_storage_base &&) = default; + expected_storage_base &operator=(const expected_storage_base &) = default; + expected_storage_base &operator=(expected_storage_base &&) = default; + ~expected_storage_base() { + if (m_has_val) { + m_val.~T(); + } + } + union { + T m_val; + unexpected m_unexpect; + char m_no_init; + }; + bool m_has_val; +}; + +// `T` is `void`, `E` is trivially-destructible +template struct expected_storage_base { + #if __GNUC__ <= 5 + //no constexpr for GCC 4/5 bug + #else + TL_EXPECTED_MSVC2015_CONSTEXPR + #endif + expected_storage_base() : m_has_val(true) {} + + constexpr expected_storage_base(no_init_t) : m_val(), m_has_val(false) {} + + constexpr expected_storage_base(in_place_t) : m_has_val(true) {} + + template ::value> * = + nullptr> + constexpr explicit expected_storage_base(unexpect_t, Args &&...args) + : m_unexpect(std::forward(args)...), m_has_val(false) {} + + template &, Args &&...>::value> * = nullptr> + constexpr explicit expected_storage_base(unexpect_t, + std::initializer_list il, + Args &&...args) + : m_unexpect(il, std::forward(args)...), m_has_val(false) {} + + expected_storage_base(const expected_storage_base &) = default; + expected_storage_base(expected_storage_base &&) = default; + expected_storage_base &operator=(const expected_storage_base &) = default; + expected_storage_base &operator=(expected_storage_base &&) = default; + ~expected_storage_base() = default; + struct dummy {}; + union { + unexpected m_unexpect; + dummy m_val; + }; + bool m_has_val; +}; + +// `T` is `void`, `E` is not trivially-destructible +template struct expected_storage_base { + constexpr expected_storage_base() : m_dummy(), m_has_val(true) {} + constexpr expected_storage_base(no_init_t) : m_dummy(), m_has_val(false) {} + + constexpr expected_storage_base(in_place_t) : m_dummy(), m_has_val(true) {} + + template ::value> * = + nullptr> + constexpr explicit expected_storage_base(unexpect_t, Args &&...args) + : m_unexpect(std::forward(args)...), m_has_val(false) {} + + template &, Args &&...>::value> * = nullptr> + constexpr explicit expected_storage_base(unexpect_t, + std::initializer_list il, + Args &&...args) + : m_unexpect(il, std::forward(args)...), m_has_val(false) {} + + expected_storage_base(const expected_storage_base &) = default; + expected_storage_base(expected_storage_base &&) = default; + expected_storage_base &operator=(const expected_storage_base &) = default; + expected_storage_base &operator=(expected_storage_base &&) = default; + ~expected_storage_base() { + if (!m_has_val) { + m_unexpect.~unexpected(); + } + } + + union { + unexpected m_unexpect; + char m_dummy; + }; + bool m_has_val; +}; + +// This base class provides some handy member functions which can be used in +// further derived classes +template +struct expected_operations_base : expected_storage_base { + using expected_storage_base::expected_storage_base; + + template void construct(Args &&...args) noexcept { + new (std::addressof(this->m_val)) T(std::forward(args)...); + this->m_has_val = true; + } + + template void construct_with(Rhs &&rhs) noexcept { + new (std::addressof(this->m_val)) T(std::forward(rhs).get()); + this->m_has_val = true; + } + + template void construct_error(Args &&...args) noexcept { + new (std::addressof(this->m_unexpect)) + unexpected(std::forward(args)...); + this->m_has_val = false; + } + +#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED + + // These assign overloads ensure that the most efficient assignment + // implementation is used while maintaining the strong exception guarantee. + // The problematic case is where rhs has a value, but *this does not. + // + // This overload handles the case where we can just copy-construct `T` + // directly into place without throwing. + template ::value> + * = nullptr> + void assign(const expected_operations_base &rhs) noexcept { + if (!this->m_has_val && rhs.m_has_val) { + geterr().~unexpected(); + construct(rhs.get()); + } else { + assign_common(rhs); + } + } + + // This overload handles the case where we can attempt to create a copy of + // `T`, then no-throw move it into place if the copy was successful. + template ::value && + std::is_nothrow_move_constructible::value> + * = nullptr> + void assign(const expected_operations_base &rhs) noexcept { + if (!this->m_has_val && rhs.m_has_val) { + T tmp = rhs.get(); + geterr().~unexpected(); + construct(std::move(tmp)); + } else { + assign_common(rhs); + } + } + + // This overload is the worst-case, where we have to move-construct the + // unexpected value into temporary storage, then try to copy the T into place. + // If the construction succeeds, then everything is fine, but if it throws, + // then we move the old unexpected value back into place before rethrowing the + // exception. + template ::value && + !std::is_nothrow_move_constructible::value> + * = nullptr> + void assign(const expected_operations_base &rhs) { + if (!this->m_has_val && rhs.m_has_val) { + auto tmp = std::move(geterr()); + geterr().~unexpected(); + +#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED + try { + construct(rhs.get()); + } catch (...) { + geterr() = std::move(tmp); + throw; + } +#else + construct(rhs.get()); +#endif + } else { + assign_common(rhs); + } + } + + // These overloads do the same as above, but for rvalues + template ::value> + * = nullptr> + void assign(expected_operations_base &&rhs) noexcept { + if (!this->m_has_val && rhs.m_has_val) { + geterr().~unexpected(); + construct(std::move(rhs).get()); + } else { + assign_common(std::move(rhs)); + } + } + + template ::value> + * = nullptr> + void assign(expected_operations_base &&rhs) { + if (!this->m_has_val && rhs.m_has_val) { + auto tmp = std::move(geterr()); + geterr().~unexpected(); +#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED + try { + construct(std::move(rhs).get()); + } catch (...) { + geterr() = std::move(tmp); + throw; + } +#else + construct(std::move(rhs).get()); +#endif + } else { + assign_common(std::move(rhs)); + } + } + +#else + + // If exceptions are disabled then we can just copy-construct + void assign(const expected_operations_base &rhs) noexcept { + if (!this->m_has_val && rhs.m_has_val) { + geterr().~unexpected(); + construct(rhs.get()); + } else { + assign_common(rhs); + } + } + + void assign(expected_operations_base &&rhs) noexcept { + if (!this->m_has_val && rhs.m_has_val) { + geterr().~unexpected(); + construct(std::move(rhs).get()); + } else { + assign_common(std::move(rhs)); + } + } + +#endif + + // The common part of move/copy assigning + template void assign_common(Rhs &&rhs) { + if (this->m_has_val) { + if (rhs.m_has_val) { + get() = std::forward(rhs).get(); + } else { + destroy_val(); + construct_error(std::forward(rhs).geterr()); + } + } else { + if (!rhs.m_has_val) { + geterr() = std::forward(rhs).geterr(); + } + } + } + + bool has_value() const { return this->m_has_val; } + + TL_EXPECTED_11_CONSTEXPR T &get() & { return this->m_val; } + constexpr const T &get() const & { return this->m_val; } + TL_EXPECTED_11_CONSTEXPR T &&get() && { return std::move(this->m_val); } +#ifndef TL_EXPECTED_NO_CONSTRR + constexpr const T &&get() const && { return std::move(this->m_val); } +#endif + + TL_EXPECTED_11_CONSTEXPR unexpected &geterr() & { + return this->m_unexpect; + } + constexpr const unexpected &geterr() const & { return this->m_unexpect; } + TL_EXPECTED_11_CONSTEXPR unexpected &&geterr() && { + return std::move(this->m_unexpect); + } +#ifndef TL_EXPECTED_NO_CONSTRR + constexpr const unexpected &&geterr() const && { + return std::move(this->m_unexpect); + } +#endif + + TL_EXPECTED_11_CONSTEXPR void destroy_val() { get().~T(); } +}; + +// This base class provides some handy member functions which can be used in +// further derived classes +template +struct expected_operations_base : expected_storage_base { + using expected_storage_base::expected_storage_base; + + template void construct() noexcept { this->m_has_val = true; } + + // This function doesn't use its argument, but needs it so that code in + // levels above this can work independently of whether T is void + template void construct_with(Rhs &&) noexcept { + this->m_has_val = true; + } + + template void construct_error(Args &&...args) noexcept { + new (std::addressof(this->m_unexpect)) + unexpected(std::forward(args)...); + this->m_has_val = false; + } + + template void assign(Rhs &&rhs) noexcept { + if (!this->m_has_val) { + if (rhs.m_has_val) { + geterr().~unexpected(); + construct(); + } else { + geterr() = std::forward(rhs).geterr(); + } + } else { + if (!rhs.m_has_val) { + construct_error(std::forward(rhs).geterr()); + } + } + } + + bool has_value() const { return this->m_has_val; } + + TL_EXPECTED_11_CONSTEXPR unexpected &geterr() & { + return this->m_unexpect; + } + constexpr const unexpected &geterr() const & { return this->m_unexpect; } + TL_EXPECTED_11_CONSTEXPR unexpected &&geterr() && { + return std::move(this->m_unexpect); + } +#ifndef TL_EXPECTED_NO_CONSTRR + constexpr const unexpected &&geterr() const && { + return std::move(this->m_unexpect); + } +#endif + + TL_EXPECTED_11_CONSTEXPR void destroy_val() { + // no-op + } +}; + +// This class manages conditionally having a trivial copy constructor +// This specialization is for when T and E are trivially copy constructible +template :: + value &&TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(E)::value, + bool = (is_copy_constructible_or_void::value && + std::is_copy_constructible::value)> +struct expected_copy_base : expected_operations_base { + using expected_operations_base::expected_operations_base; +}; + +// This specialization is for when T or E are non-trivially copy constructible +template +struct expected_copy_base : expected_operations_base { + using expected_operations_base::expected_operations_base; + + expected_copy_base() = default; + expected_copy_base(const expected_copy_base &rhs) + : expected_operations_base(no_init) { + if (rhs.has_value()) { + this->construct_with(rhs); + } else { + this->construct_error(rhs.geterr()); + } + } + + expected_copy_base(expected_copy_base &&rhs) = default; + expected_copy_base &operator=(const expected_copy_base &rhs) = default; + expected_copy_base &operator=(expected_copy_base &&rhs) = default; +}; + +// This class manages conditionally having a trivial move constructor +// Unfortunately there's no way to achieve this in GCC < 5 AFAIK, since it +// doesn't implement an analogue to std::is_trivially_move_constructible. We +// have to make do with a non-trivial move constructor even if T is trivially +// move constructible +#ifndef TL_EXPECTED_GCC49 +template >::value + &&std::is_trivially_move_constructible::value> +struct expected_move_base : expected_copy_base { + using expected_copy_base::expected_copy_base; +}; +#else +template struct expected_move_base; +#endif +template +struct expected_move_base : expected_copy_base { + using expected_copy_base::expected_copy_base; + + expected_move_base() = default; + expected_move_base(const expected_move_base &rhs) = default; + + expected_move_base(expected_move_base &&rhs) noexcept( + std::is_nothrow_move_constructible::value) + : expected_copy_base(no_init) { + if (rhs.has_value()) { + this->construct_with(std::move(rhs)); + } else { + this->construct_error(std::move(rhs.geterr())); + } + } + expected_move_base &operator=(const expected_move_base &rhs) = default; + expected_move_base &operator=(expected_move_base &&rhs) = default; +}; + +// This class manages conditionally having a trivial copy assignment operator +template >::value + &&TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(E)::value + &&TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(E)::value + &&TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(E)::value, + bool = (is_copy_constructible_or_void::value && + std::is_copy_constructible::value && + is_copy_assignable_or_void::value && + std::is_copy_assignable::value)> +struct expected_copy_assign_base : expected_move_base { + using expected_move_base::expected_move_base; +}; + +template +struct expected_copy_assign_base : expected_move_base { + using expected_move_base::expected_move_base; + + expected_copy_assign_base() = default; + expected_copy_assign_base(const expected_copy_assign_base &rhs) = default; + + expected_copy_assign_base(expected_copy_assign_base &&rhs) = default; + expected_copy_assign_base &operator=(const expected_copy_assign_base &rhs) { + this->assign(rhs); + return *this; + } + expected_copy_assign_base & + operator=(expected_copy_assign_base &&rhs) = default; +}; + +// This class manages conditionally having a trivial move assignment operator +// Unfortunately there's no way to achieve this in GCC < 5 AFAIK, since it +// doesn't implement an analogue to std::is_trivially_move_assignable. We have +// to make do with a non-trivial move assignment operator even if T is trivially +// move assignable +#ifndef TL_EXPECTED_GCC49 +template , + std::is_trivially_move_constructible, + std::is_trivially_move_assignable>>:: + value &&std::is_trivially_destructible::value + &&std::is_trivially_move_constructible::value + &&std::is_trivially_move_assignable::value> +struct expected_move_assign_base : expected_copy_assign_base { + using expected_copy_assign_base::expected_copy_assign_base; +}; +#else +template struct expected_move_assign_base; +#endif + +template +struct expected_move_assign_base + : expected_copy_assign_base { + using expected_copy_assign_base::expected_copy_assign_base; + + expected_move_assign_base() = default; + expected_move_assign_base(const expected_move_assign_base &rhs) = default; + + expected_move_assign_base(expected_move_assign_base &&rhs) = default; + + expected_move_assign_base & + operator=(const expected_move_assign_base &rhs) = default; + + expected_move_assign_base & + operator=(expected_move_assign_base &&rhs) noexcept( + std::is_nothrow_move_constructible::value + &&std::is_nothrow_move_assignable::value) { + this->assign(std::move(rhs)); + return *this; + } +}; + +// expected_delete_ctor_base will conditionally delete copy and move +// constructors depending on whether T is copy/move constructible +template ::value && + std::is_copy_constructible::value), + bool EnableMove = (is_move_constructible_or_void::value && + std::is_move_constructible::value)> +struct expected_delete_ctor_base { + expected_delete_ctor_base() = default; + expected_delete_ctor_base(const expected_delete_ctor_base &) = default; + expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept = default; + expected_delete_ctor_base & + operator=(const expected_delete_ctor_base &) = default; + expected_delete_ctor_base & + operator=(expected_delete_ctor_base &&) noexcept = default; +}; + +template +struct expected_delete_ctor_base { + expected_delete_ctor_base() = default; + expected_delete_ctor_base(const expected_delete_ctor_base &) = default; + expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept = delete; + expected_delete_ctor_base & + operator=(const expected_delete_ctor_base &) = default; + expected_delete_ctor_base & + operator=(expected_delete_ctor_base &&) noexcept = default; +}; + +template +struct expected_delete_ctor_base { + expected_delete_ctor_base() = default; + expected_delete_ctor_base(const expected_delete_ctor_base &) = delete; + expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept = default; + expected_delete_ctor_base & + operator=(const expected_delete_ctor_base &) = default; + expected_delete_ctor_base & + operator=(expected_delete_ctor_base &&) noexcept = default; +}; + +template +struct expected_delete_ctor_base { + expected_delete_ctor_base() = default; + expected_delete_ctor_base(const expected_delete_ctor_base &) = delete; + expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept = delete; + expected_delete_ctor_base & + operator=(const expected_delete_ctor_base &) = default; + expected_delete_ctor_base & + operator=(expected_delete_ctor_base &&) noexcept = default; +}; + +// expected_delete_assign_base will conditionally delete copy and move +// constructors depending on whether T and E are copy/move constructible + +// assignable +template ::value && + std::is_copy_constructible::value && + is_copy_assignable_or_void::value && + std::is_copy_assignable::value), + bool EnableMove = (is_move_constructible_or_void::value && + std::is_move_constructible::value && + is_move_assignable_or_void::value && + std::is_move_assignable::value)> +struct expected_delete_assign_base { + expected_delete_assign_base() = default; + expected_delete_assign_base(const expected_delete_assign_base &) = default; + expected_delete_assign_base(expected_delete_assign_base &&) noexcept = + default; + expected_delete_assign_base & + operator=(const expected_delete_assign_base &) = default; + expected_delete_assign_base & + operator=(expected_delete_assign_base &&) noexcept = default; +}; + +template +struct expected_delete_assign_base { + expected_delete_assign_base() = default; + expected_delete_assign_base(const expected_delete_assign_base &) = default; + expected_delete_assign_base(expected_delete_assign_base &&) noexcept = + default; + expected_delete_assign_base & + operator=(const expected_delete_assign_base &) = default; + expected_delete_assign_base & + operator=(expected_delete_assign_base &&) noexcept = delete; +}; + +template +struct expected_delete_assign_base { + expected_delete_assign_base() = default; + expected_delete_assign_base(const expected_delete_assign_base &) = default; + expected_delete_assign_base(expected_delete_assign_base &&) noexcept = + default; + expected_delete_assign_base & + operator=(const expected_delete_assign_base &) = delete; + expected_delete_assign_base & + operator=(expected_delete_assign_base &&) noexcept = default; +}; + +template +struct expected_delete_assign_base { + expected_delete_assign_base() = default; + expected_delete_assign_base(const expected_delete_assign_base &) = default; + expected_delete_assign_base(expected_delete_assign_base &&) noexcept = + default; + expected_delete_assign_base & + operator=(const expected_delete_assign_base &) = delete; + expected_delete_assign_base & + operator=(expected_delete_assign_base &&) noexcept = delete; +}; + +// This is needed to be able to construct the expected_default_ctor_base which +// follows, while still conditionally deleting the default constructor. +struct default_constructor_tag { + explicit constexpr default_constructor_tag() = default; +}; + +// expected_default_ctor_base will ensure that expected has a deleted default +// constructor if T is not default constructible. +// This specialization is for when T is default constructible +template ::value || std::is_void::value> +struct expected_default_ctor_base { + constexpr expected_default_ctor_base() noexcept = default; + constexpr expected_default_ctor_base( + expected_default_ctor_base const &) noexcept = default; + constexpr expected_default_ctor_base(expected_default_ctor_base &&) noexcept = + default; + expected_default_ctor_base & + operator=(expected_default_ctor_base const &) noexcept = default; + expected_default_ctor_base & + operator=(expected_default_ctor_base &&) noexcept = default; + + constexpr explicit expected_default_ctor_base(default_constructor_tag) {} +}; + +// This specialization is for when T is not default constructible +template struct expected_default_ctor_base { + constexpr expected_default_ctor_base() noexcept = delete; + constexpr expected_default_ctor_base( + expected_default_ctor_base const &) noexcept = default; + constexpr expected_default_ctor_base(expected_default_ctor_base &&) noexcept = + default; + expected_default_ctor_base & + operator=(expected_default_ctor_base const &) noexcept = default; + expected_default_ctor_base & + operator=(expected_default_ctor_base &&) noexcept = default; + + constexpr explicit expected_default_ctor_base(default_constructor_tag) {} +}; +} // namespace detail + +template class bad_expected_access : public std::exception { +public: + explicit bad_expected_access(E e) : m_val(std::move(e)) {} + + virtual const char *what() const noexcept override { + return "Bad expected access"; + } + + const E &error() const & { return m_val; } + E &error() & { return m_val; } + const E &&error() const && { return std::move(m_val); } + E &&error() && { return std::move(m_val); } + +private: + E m_val; +}; + +/// An `expected` object is an object that contains the storage for +/// another object and manages the lifetime of this contained object `T`. +/// Alternatively it could contain the storage for another unexpected object +/// `E`. The contained object may not be initialized after the expected object +/// has been initialized, and may not be destroyed before the expected object +/// has been destroyed. The initialization state of the contained object is +/// tracked by the expected object. +template +class TL_EXPECTED_NODISCARD expected : + private detail::expected_move_assign_base, + private detail::expected_delete_ctor_base, + private detail::expected_delete_assign_base, + private detail::expected_default_ctor_base { + static_assert(!std::is_reference::value, "T must not be a reference"); + static_assert(!std::is_same::type>::value, + "T must not be in_place_t"); + static_assert(!std::is_same::type>::value, + "T must not be unexpect_t"); + static_assert( + !std::is_same>::type>::value, + "T must not be unexpected"); + static_assert(!std::is_reference::value, "E must not be a reference"); + + T *valptr() { return std::addressof(this->m_val); } + const T *valptr() const { return std::addressof(this->m_val); } + unexpected *errptr() { return std::addressof(this->m_unexpect); } + const unexpected *errptr() const { + return std::addressof(this->m_unexpect); + } + + template ::value> * = nullptr> + TL_EXPECTED_11_CONSTEXPR U &val() { + return this->m_val; + } + TL_EXPECTED_11_CONSTEXPR unexpected &err() { return this->m_unexpect; } + + template ::value> * = nullptr> + constexpr const U &val() const { + return this->m_val; + } + constexpr const unexpected &err() const { return this->m_unexpect; } + + using impl_base = detail::expected_move_assign_base; + using ctor_base = detail::expected_default_ctor_base; + +public: + typedef T value_type; + typedef E error_type; + typedef unexpected unexpected_type; + +#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \ + !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55) + template TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) & { + return and_then_impl(*this, std::forward(f)); + } + template TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) && { + return and_then_impl(std::move(*this), std::forward(f)); + } + template constexpr auto and_then(F &&f) const & { + return and_then_impl(*this, std::forward(f)); + } + +#ifndef TL_EXPECTED_NO_CONSTRR + template constexpr auto and_then(F &&f) const && { + return and_then_impl(std::move(*this), std::forward(f)); + } +#endif + +#else + template + TL_EXPECTED_11_CONSTEXPR auto + and_then(F &&f) & -> decltype(and_then_impl(std::declval(), + std::forward(f))) { + return and_then_impl(*this, std::forward(f)); + } + template + TL_EXPECTED_11_CONSTEXPR auto + and_then(F &&f) && -> decltype(and_then_impl(std::declval(), + std::forward(f))) { + return and_then_impl(std::move(*this), std::forward(f)); + } + template + constexpr auto and_then(F &&f) const & -> decltype(and_then_impl( + std::declval(), std::forward(f))) { + return and_then_impl(*this, std::forward(f)); + } + +#ifndef TL_EXPECTED_NO_CONSTRR + template + constexpr auto and_then(F &&f) const && -> decltype(and_then_impl( + std::declval(), std::forward(f))) { + return and_then_impl(std::move(*this), std::forward(f)); + } +#endif +#endif + +#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \ + !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55) + template TL_EXPECTED_11_CONSTEXPR auto map(F &&f) & { + return expected_map_impl(*this, std::forward(f)); + } + template TL_EXPECTED_11_CONSTEXPR auto map(F &&f) && { + return expected_map_impl(std::move(*this), std::forward(f)); + } + template constexpr auto map(F &&f) const & { + return expected_map_impl(*this, std::forward(f)); + } + template constexpr auto map(F &&f) const && { + return expected_map_impl(std::move(*this), std::forward(f)); + } +#else + template + TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl( + std::declval(), std::declval())) + map(F &&f) & { + return expected_map_impl(*this, std::forward(f)); + } + template + TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(std::declval(), + std::declval())) + map(F &&f) && { + return expected_map_impl(std::move(*this), std::forward(f)); + } + template + constexpr decltype(expected_map_impl(std::declval(), + std::declval())) + map(F &&f) const & { + return expected_map_impl(*this, std::forward(f)); + } + +#ifndef TL_EXPECTED_NO_CONSTRR + template + constexpr decltype(expected_map_impl(std::declval(), + std::declval())) + map(F &&f) const && { + return expected_map_impl(std::move(*this), std::forward(f)); + } +#endif +#endif + +#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \ + !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55) + template TL_EXPECTED_11_CONSTEXPR auto transform(F &&f) & { + return expected_map_impl(*this, std::forward(f)); + } + template TL_EXPECTED_11_CONSTEXPR auto transform(F &&f) && { + return expected_map_impl(std::move(*this), std::forward(f)); + } + template constexpr auto transform(F &&f) const & { + return expected_map_impl(*this, std::forward(f)); + } + template constexpr auto transform(F &&f) const && { + return expected_map_impl(std::move(*this), std::forward(f)); + } +#else + template + TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl( + std::declval(), std::declval())) + transform(F &&f) & { + return expected_map_impl(*this, std::forward(f)); + } + template + TL_EXPECTED_11_CONSTEXPR decltype(expected_map_impl(std::declval(), + std::declval())) + transform(F &&f) && { + return expected_map_impl(std::move(*this), std::forward(f)); + } + template + constexpr decltype(expected_map_impl(std::declval(), + std::declval())) + transform(F &&f) const & { + return expected_map_impl(*this, std::forward(f)); + } + +#ifndef TL_EXPECTED_NO_CONSTRR + template + constexpr decltype(expected_map_impl(std::declval(), + std::declval())) + transform(F &&f) const && { + return expected_map_impl(std::move(*this), std::forward(f)); + } +#endif +#endif + +#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \ + !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55) + template TL_EXPECTED_11_CONSTEXPR auto map_error(F &&f) & { + return map_error_impl(*this, std::forward(f)); + } + template TL_EXPECTED_11_CONSTEXPR auto map_error(F &&f) && { + return map_error_impl(std::move(*this), std::forward(f)); + } + template constexpr auto map_error(F &&f) const & { + return map_error_impl(*this, std::forward(f)); + } + template constexpr auto map_error(F &&f) const && { + return map_error_impl(std::move(*this), std::forward(f)); + } +#else + template + TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval(), + std::declval())) + map_error(F &&f) & { + return map_error_impl(*this, std::forward(f)); + } + template + TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval(), + std::declval())) + map_error(F &&f) && { + return map_error_impl(std::move(*this), std::forward(f)); + } + template + constexpr decltype(map_error_impl(std::declval(), + std::declval())) + map_error(F &&f) const & { + return map_error_impl(*this, std::forward(f)); + } + +#ifndef TL_EXPECTED_NO_CONSTRR + template + constexpr decltype(map_error_impl(std::declval(), + std::declval())) + map_error(F &&f) const && { + return map_error_impl(std::move(*this), std::forward(f)); + } +#endif +#endif +#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \ + !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55) + template TL_EXPECTED_11_CONSTEXPR auto transform_error(F &&f) & { + return map_error_impl(*this, std::forward(f)); + } + template TL_EXPECTED_11_CONSTEXPR auto transform_error(F &&f) && { + return map_error_impl(std::move(*this), std::forward(f)); + } + template constexpr auto transform_error(F &&f) const & { + return map_error_impl(*this, std::forward(f)); + } + template constexpr auto transform_error(F &&f) const && { + return map_error_impl(std::move(*this), std::forward(f)); + } +#else + template + TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval(), + std::declval())) + transform_error(F &&f) & { + return map_error_impl(*this, std::forward(f)); + } + template + TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval(), + std::declval())) + transform_error(F &&f) && { + return map_error_impl(std::move(*this), std::forward(f)); + } + template + constexpr decltype(map_error_impl(std::declval(), + std::declval())) + transform_error(F &&f) const & { + return map_error_impl(*this, std::forward(f)); + } + +#ifndef TL_EXPECTED_NO_CONSTRR + template + constexpr decltype(map_error_impl(std::declval(), + std::declval())) + transform_error(F &&f) const && { + return map_error_impl(std::move(*this), std::forward(f)); + } +#endif +#endif + template expected TL_EXPECTED_11_CONSTEXPR or_else(F &&f) & { + return or_else_impl(*this, std::forward(f)); + } + + template expected TL_EXPECTED_11_CONSTEXPR or_else(F &&f) && { + return or_else_impl(std::move(*this), std::forward(f)); + } + + template expected constexpr or_else(F &&f) const & { + return or_else_impl(*this, std::forward(f)); + } + +#ifndef TL_EXPECTED_NO_CONSTRR + template expected constexpr or_else(F &&f) const && { + return or_else_impl(std::move(*this), std::forward(f)); + } +#endif + constexpr expected() = default; + constexpr expected(const expected &rhs) = default; + constexpr expected(expected &&rhs) = default; + expected &operator=(const expected &rhs) = default; + expected &operator=(expected &&rhs) = default; + + template ::value> * = + nullptr> + constexpr expected(in_place_t, Args &&...args) + : impl_base(in_place, std::forward(args)...), + ctor_base(detail::default_constructor_tag{}) {} + + template &, Args &&...>::value> * = nullptr> + constexpr expected(in_place_t, std::initializer_list il, Args &&...args) + : impl_base(in_place, il, std::forward(args)...), + ctor_base(detail::default_constructor_tag{}) {} + + template ::value> * = + nullptr, + detail::enable_if_t::value> * = + nullptr> + explicit constexpr expected(const unexpected &e) + : impl_base(unexpect, e.value()), + ctor_base(detail::default_constructor_tag{}) {} + + template < + class G = E, + detail::enable_if_t::value> * = + nullptr, + detail::enable_if_t::value> * = nullptr> + constexpr expected(unexpected const &e) + : impl_base(unexpect, e.value()), + ctor_base(detail::default_constructor_tag{}) {} + + template < + class G = E, + detail::enable_if_t::value> * = nullptr, + detail::enable_if_t::value> * = nullptr> + explicit constexpr expected(unexpected &&e) noexcept( + std::is_nothrow_constructible::value) + : impl_base(unexpect, std::move(e.value())), + ctor_base(detail::default_constructor_tag{}) {} + + template < + class G = E, + detail::enable_if_t::value> * = nullptr, + detail::enable_if_t::value> * = nullptr> + constexpr expected(unexpected &&e) noexcept( + std::is_nothrow_constructible::value) + : impl_base(unexpect, std::move(e.value())), + ctor_base(detail::default_constructor_tag{}) {} + + template ::value> * = + nullptr> + constexpr explicit expected(unexpect_t, Args &&...args) + : impl_base(unexpect, std::forward(args)...), + ctor_base(detail::default_constructor_tag{}) {} + + template &, Args &&...>::value> * = nullptr> + constexpr explicit expected(unexpect_t, std::initializer_list il, + Args &&...args) + : impl_base(unexpect, il, std::forward(args)...), + ctor_base(detail::default_constructor_tag{}) {} + + template ::value && + std::is_convertible::value)> * = + nullptr, + detail::expected_enable_from_other + * = nullptr> + explicit TL_EXPECTED_11_CONSTEXPR expected(const expected &rhs) + : ctor_base(detail::default_constructor_tag{}) { + if (rhs.has_value()) { + this->construct(*rhs); + } else { + this->construct_error(rhs.error()); + } + } + + template ::value && + std::is_convertible::value)> * = + nullptr, + detail::expected_enable_from_other + * = nullptr> + TL_EXPECTED_11_CONSTEXPR expected(const expected &rhs) + : ctor_base(detail::default_constructor_tag{}) { + if (rhs.has_value()) { + this->construct(*rhs); + } else { + this->construct_error(rhs.error()); + } + } + + template < + class U, class G, + detail::enable_if_t::value && + std::is_convertible::value)> * = nullptr, + detail::expected_enable_from_other * = nullptr> + explicit TL_EXPECTED_11_CONSTEXPR expected(expected &&rhs) + : ctor_base(detail::default_constructor_tag{}) { + if (rhs.has_value()) { + this->construct(std::move(*rhs)); + } else { + this->construct_error(std::move(rhs.error())); + } + } + + template < + class U, class G, + detail::enable_if_t<(std::is_convertible::value && + std::is_convertible::value)> * = nullptr, + detail::expected_enable_from_other * = nullptr> + TL_EXPECTED_11_CONSTEXPR expected(expected &&rhs) + : ctor_base(detail::default_constructor_tag{}) { + if (rhs.has_value()) { + this->construct(std::move(*rhs)); + } else { + this->construct_error(std::move(rhs.error())); + } + } + + template < + class U = T, + detail::enable_if_t::value> * = nullptr, + detail::expected_enable_forward_value * = nullptr> + explicit TL_EXPECTED_MSVC2015_CONSTEXPR expected(U &&v) + : expected(in_place, std::forward(v)) {} + + template < + class U = T, + detail::enable_if_t::value> * = nullptr, + detail::expected_enable_forward_value * = nullptr> + TL_EXPECTED_MSVC2015_CONSTEXPR expected(U &&v) + : expected(in_place, std::forward(v)) {} + + template < + class U = T, class G = T, + detail::enable_if_t::value> * = + nullptr, + detail::enable_if_t::value> * = nullptr, + detail::enable_if_t< + (!std::is_same, detail::decay_t>::value && + !detail::conjunction, + std::is_same>>::value && + std::is_constructible::value && + std::is_assignable::value && + std::is_nothrow_move_constructible::value)> * = nullptr> + expected &operator=(U &&v) { + if (has_value()) { + val() = std::forward(v); + } else { + err().~unexpected(); + ::new (valptr()) T(std::forward(v)); + this->m_has_val = true; + } + + return *this; + } + + template < + class U = T, class G = T, + detail::enable_if_t::value> * = + nullptr, + detail::enable_if_t::value> * = nullptr, + detail::enable_if_t< + (!std::is_same, detail::decay_t>::value && + !detail::conjunction, + std::is_same>>::value && + std::is_constructible::value && + std::is_assignable::value && + std::is_nothrow_move_constructible::value)> * = nullptr> + expected &operator=(U &&v) { + if (has_value()) { + val() = std::forward(v); + } else { + auto tmp = std::move(err()); + err().~unexpected(); + +#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED + try { + ::new (valptr()) T(std::forward(v)); + this->m_has_val = true; + } catch (...) { + err() = std::move(tmp); + throw; + } +#else + ::new (valptr()) T(std::forward(v)); + this->m_has_val = true; +#endif + } + + return *this; + } + + template ::value && + std::is_assignable::value> * = nullptr> + expected &operator=(const unexpected &rhs) { + if (!has_value()) { + err() = rhs; + } else { + this->destroy_val(); + ::new (errptr()) unexpected(rhs); + this->m_has_val = false; + } + + return *this; + } + + template ::value && + std::is_move_assignable::value> * = nullptr> + expected &operator=(unexpected &&rhs) noexcept { + if (!has_value()) { + err() = std::move(rhs); + } else { + this->destroy_val(); + ::new (errptr()) unexpected(std::move(rhs)); + this->m_has_val = false; + } + + return *this; + } + + template ::value> * = nullptr> + void emplace(Args &&...args) { + if (has_value()) { + val().~T(); + } else { + err().~unexpected(); + this->m_has_val = true; + } + ::new (valptr()) T(std::forward(args)...); + } + + template ::value> * = nullptr> + void emplace(Args &&...args) { + if (has_value()) { + val().~T(); + ::new (valptr()) T(std::forward(args)...); + } else { + auto tmp = std::move(err()); + err().~unexpected(); + +#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED + try { + ::new (valptr()) T(std::forward(args)...); + this->m_has_val = true; + } catch (...) { + err() = std::move(tmp); + throw; + } +#else + ::new (valptr()) T(std::forward(args)...); + this->m_has_val = true; +#endif + } + } + + template &, Args &&...>::value> * = nullptr> + void emplace(std::initializer_list il, Args &&...args) { + if (has_value()) { + T t(il, std::forward(args)...); + val() = std::move(t); + } else { + err().~unexpected(); + ::new (valptr()) T(il, std::forward(args)...); + this->m_has_val = true; + } + } + + template &, Args &&...>::value> * = nullptr> + void emplace(std::initializer_list il, Args &&...args) { + if (has_value()) { + T t(il, std::forward(args)...); + val() = std::move(t); + } else { + auto tmp = std::move(err()); + err().~unexpected(); + +#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED + try { + ::new (valptr()) T(il, std::forward(args)...); + this->m_has_val = true; + } catch (...) { + err() = std::move(tmp); + throw; + } +#else + ::new (valptr()) T(il, std::forward(args)...); + this->m_has_val = true; +#endif + } + } + +private: + using t_is_void = std::true_type; + using t_is_not_void = std::false_type; + using t_is_nothrow_move_constructible = std::true_type; + using move_constructing_t_can_throw = std::false_type; + using e_is_nothrow_move_constructible = std::true_type; + using move_constructing_e_can_throw = std::false_type; + + void swap_where_both_have_value(expected & /*rhs*/, t_is_void) noexcept { + // swapping void is a no-op + } + + void swap_where_both_have_value(expected &rhs, t_is_not_void) { + using std::swap; + swap(val(), rhs.val()); + } + + void swap_where_only_one_has_value(expected &rhs, t_is_void) noexcept( + std::is_nothrow_move_constructible::value) { + ::new (errptr()) unexpected_type(std::move(rhs.err())); + rhs.err().~unexpected_type(); + std::swap(this->m_has_val, rhs.m_has_val); + } + + void swap_where_only_one_has_value(expected &rhs, t_is_not_void) { + swap_where_only_one_has_value_and_t_is_not_void( + rhs, typename std::is_nothrow_move_constructible::type{}, + typename std::is_nothrow_move_constructible::type{}); + } + + void swap_where_only_one_has_value_and_t_is_not_void( + expected &rhs, t_is_nothrow_move_constructible, + e_is_nothrow_move_constructible) noexcept { + auto temp = std::move(val()); + val().~T(); + ::new (errptr()) unexpected_type(std::move(rhs.err())); + rhs.err().~unexpected_type(); + ::new (rhs.valptr()) T(std::move(temp)); + std::swap(this->m_has_val, rhs.m_has_val); + } + + void swap_where_only_one_has_value_and_t_is_not_void( + expected &rhs, t_is_nothrow_move_constructible, + move_constructing_e_can_throw) { + auto temp = std::move(val()); + val().~T(); +#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED + try { + ::new (errptr()) unexpected_type(std::move(rhs.err())); + rhs.err().~unexpected_type(); + ::new (rhs.valptr()) T(std::move(temp)); + std::swap(this->m_has_val, rhs.m_has_val); + } catch (...) { + val() = std::move(temp); + throw; + } +#else + ::new (errptr()) unexpected_type(std::move(rhs.err())); + rhs.err().~unexpected_type(); + ::new (rhs.valptr()) T(std::move(temp)); + std::swap(this->m_has_val, rhs.m_has_val); +#endif + } + + void swap_where_only_one_has_value_and_t_is_not_void( + expected &rhs, move_constructing_t_can_throw, + e_is_nothrow_move_constructible) { + auto temp = std::move(rhs.err()); + rhs.err().~unexpected_type(); +#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED + try { + ::new (rhs.valptr()) T(std::move(val())); + val().~T(); + ::new (errptr()) unexpected_type(std::move(temp)); + std::swap(this->m_has_val, rhs.m_has_val); + } catch (...) { + rhs.err() = std::move(temp); + throw; + } +#else + ::new (rhs.valptr()) T(std::move(val())); + val().~T(); + ::new (errptr()) unexpected_type(std::move(temp)); + std::swap(this->m_has_val, rhs.m_has_val); +#endif + } + +public: + template + detail::enable_if_t::value && + detail::is_swappable::value && + (std::is_nothrow_move_constructible::value || + std::is_nothrow_move_constructible::value)> + swap(expected &rhs) noexcept( + std::is_nothrow_move_constructible::value + &&detail::is_nothrow_swappable::value + &&std::is_nothrow_move_constructible::value + &&detail::is_nothrow_swappable::value) { + if (has_value() && rhs.has_value()) { + swap_where_both_have_value(rhs, typename std::is_void::type{}); + } else if (!has_value() && rhs.has_value()) { + rhs.swap(*this); + } else if (has_value()) { + swap_where_only_one_has_value(rhs, typename std::is_void::type{}); + } else { + using std::swap; + swap(err(), rhs.err()); + } + } + + constexpr const T *operator->() const { + TL_ASSERT(has_value()); + return valptr(); + } + TL_EXPECTED_11_CONSTEXPR T *operator->() { + TL_ASSERT(has_value()); + return valptr(); + } + + template ::value> * = nullptr> + constexpr const U &operator*() const & { + TL_ASSERT(has_value()); + return val(); + } + template ::value> * = nullptr> + TL_EXPECTED_11_CONSTEXPR U &operator*() & { + TL_ASSERT(has_value()); + return val(); + } + template ::value> * = nullptr> + constexpr const U &&operator*() const && { + TL_ASSERT(has_value()); + return std::move(val()); + } + template ::value> * = nullptr> + TL_EXPECTED_11_CONSTEXPR U &&operator*() && { + TL_ASSERT(has_value()); + return std::move(val()); + } + + constexpr bool has_value() const noexcept { return this->m_has_val; } + constexpr explicit operator bool() const noexcept { return this->m_has_val; } + + template ::value> * = nullptr> + TL_EXPECTED_11_CONSTEXPR const U &value() const & { + if (!has_value()) + TL_EXPECTED_THROW_EXCEPTION(bad_expected_access(err().value())); + return val(); + } + template ::value> * = nullptr> + TL_EXPECTED_11_CONSTEXPR U &value() & { + if (!has_value()) + TL_EXPECTED_THROW_EXCEPTION(bad_expected_access(err().value())); + return val(); + } + template ::value> * = nullptr> + TL_EXPECTED_11_CONSTEXPR const U &&value() const && { + if (!has_value()) + TL_EXPECTED_THROW_EXCEPTION(bad_expected_access(std::move(err()).value())); + return std::move(val()); + } + template ::value> * = nullptr> + TL_EXPECTED_11_CONSTEXPR U &&value() && { + if (!has_value()) + TL_EXPECTED_THROW_EXCEPTION(bad_expected_access(std::move(err()).value())); + return std::move(val()); + } + + constexpr const E &error() const & { + TL_ASSERT(!has_value()); + return err().value(); + } + TL_EXPECTED_11_CONSTEXPR E &error() & { + TL_ASSERT(!has_value()); + return err().value(); + } + constexpr const E &&error() const && { + TL_ASSERT(!has_value()); + return std::move(err().value()); + } + TL_EXPECTED_11_CONSTEXPR E &&error() && { + TL_ASSERT(!has_value()); + return std::move(err().value()); + } + + template constexpr T value_or(U &&v) const & { + static_assert(std::is_copy_constructible::value && + std::is_convertible::value, + "T must be copy-constructible and convertible to from U&&"); + return bool(*this) ? **this : static_cast(std::forward(v)); + } + template TL_EXPECTED_11_CONSTEXPR T value_or(U &&v) && { + static_assert(std::is_move_constructible::value && + std::is_convertible::value, + "T must be move-constructible and convertible to from U&&"); + return bool(*this) ? std::move(**this) : static_cast(std::forward(v)); + } +}; + +namespace detail { +template using exp_t = typename detail::decay_t::value_type; +template using err_t = typename detail::decay_t::error_type; +template using ret_t = expected>; + +#ifdef TL_EXPECTED_CXX14 +template >::value> * = nullptr, + class Ret = decltype(detail::invoke(std::declval(), + *std::declval()))> +constexpr auto and_then_impl(Exp &&exp, F &&f) { + static_assert(detail::is_expected::value, "F must return an expected"); + + return exp.has_value() + ? detail::invoke(std::forward(f), *std::forward(exp)) + : Ret(unexpect, std::forward(exp).error()); +} + +template >::value> * = nullptr, + class Ret = decltype(detail::invoke(std::declval()))> +constexpr auto and_then_impl(Exp &&exp, F &&f) { + static_assert(detail::is_expected::value, "F must return an expected"); + + return exp.has_value() ? detail::invoke(std::forward(f)) + : Ret(unexpect, std::forward(exp).error()); +} +#else +template struct TC; +template (), + *std::declval())), + detail::enable_if_t>::value> * = nullptr> +auto and_then_impl(Exp &&exp, F &&f) -> Ret { + static_assert(detail::is_expected::value, "F must return an expected"); + + return exp.has_value() + ? detail::invoke(std::forward(f), *std::forward(exp)) + : Ret(unexpect, std::forward(exp).error()); +} + +template ())), + detail::enable_if_t>::value> * = nullptr> +constexpr auto and_then_impl(Exp &&exp, F &&f) -> Ret { + static_assert(detail::is_expected::value, "F must return an expected"); + + return exp.has_value() ? detail::invoke(std::forward(f)) + : Ret(unexpect, std::forward(exp).error()); +} +#endif + +#ifdef TL_EXPECTED_CXX14 +template >::value> * = nullptr, + class Ret = decltype(detail::invoke(std::declval(), + *std::declval())), + detail::enable_if_t::value> * = nullptr> +constexpr auto expected_map_impl(Exp &&exp, F &&f) { + using result = ret_t>; + return exp.has_value() ? result(detail::invoke(std::forward(f), + *std::forward(exp))) + : result(unexpect, std::forward(exp).error()); +} + +template >::value> * = nullptr, + class Ret = decltype(detail::invoke(std::declval(), + *std::declval())), + detail::enable_if_t::value> * = nullptr> +auto expected_map_impl(Exp &&exp, F &&f) { + using result = expected>; + if (exp.has_value()) { + detail::invoke(std::forward(f), *std::forward(exp)); + return result(); + } + + return result(unexpect, std::forward(exp).error()); +} + +template >::value> * = nullptr, + class Ret = decltype(detail::invoke(std::declval())), + detail::enable_if_t::value> * = nullptr> +constexpr auto expected_map_impl(Exp &&exp, F &&f) { + using result = ret_t>; + return exp.has_value() ? result(detail::invoke(std::forward(f))) + : result(unexpect, std::forward(exp).error()); +} + +template >::value> * = nullptr, + class Ret = decltype(detail::invoke(std::declval())), + detail::enable_if_t::value> * = nullptr> +auto expected_map_impl(Exp &&exp, F &&f) { + using result = expected>; + if (exp.has_value()) { + detail::invoke(std::forward(f)); + return result(); + } + + return result(unexpect, std::forward(exp).error()); +} +#else +template >::value> * = nullptr, + class Ret = decltype(detail::invoke(std::declval(), + *std::declval())), + detail::enable_if_t::value> * = nullptr> + +constexpr auto expected_map_impl(Exp &&exp, F &&f) + -> ret_t> { + using result = ret_t>; + + return exp.has_value() ? result(detail::invoke(std::forward(f), + *std::forward(exp))) + : result(unexpect, std::forward(exp).error()); +} + +template >::value> * = nullptr, + class Ret = decltype(detail::invoke(std::declval(), + *std::declval())), + detail::enable_if_t::value> * = nullptr> + +auto expected_map_impl(Exp &&exp, F &&f) -> expected> { + if (exp.has_value()) { + detail::invoke(std::forward(f), *std::forward(exp)); + return {}; + } + + return unexpected>(std::forward(exp).error()); +} + +template >::value> * = nullptr, + class Ret = decltype(detail::invoke(std::declval())), + detail::enable_if_t::value> * = nullptr> + +constexpr auto expected_map_impl(Exp &&exp, F &&f) + -> ret_t> { + using result = ret_t>; + + return exp.has_value() ? result(detail::invoke(std::forward(f))) + : result(unexpect, std::forward(exp).error()); +} + +template >::value> * = nullptr, + class Ret = decltype(detail::invoke(std::declval())), + detail::enable_if_t::value> * = nullptr> + +auto expected_map_impl(Exp &&exp, F &&f) -> expected> { + if (exp.has_value()) { + detail::invoke(std::forward(f)); + return {}; + } + + return unexpected>(std::forward(exp).error()); +} +#endif + +#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \ + !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55) +template >::value> * = nullptr, + class Ret = decltype(detail::invoke(std::declval(), + std::declval().error())), + detail::enable_if_t::value> * = nullptr> +constexpr auto map_error_impl(Exp &&exp, F &&f) { + using result = expected, detail::decay_t>; + return exp.has_value() + ? result(*std::forward(exp)) + : result(unexpect, detail::invoke(std::forward(f), + std::forward(exp).error())); +} +template >::value> * = nullptr, + class Ret = decltype(detail::invoke(std::declval(), + std::declval().error())), + detail::enable_if_t::value> * = nullptr> +auto map_error_impl(Exp &&exp, F &&f) { + using result = expected, monostate>; + if (exp.has_value()) { + return result(*std::forward(exp)); + } + + detail::invoke(std::forward(f), std::forward(exp).error()); + return result(unexpect, monostate{}); +} +template >::value> * = nullptr, + class Ret = decltype(detail::invoke(std::declval(), + std::declval().error())), + detail::enable_if_t::value> * = nullptr> +constexpr auto map_error_impl(Exp &&exp, F &&f) { + using result = expected, detail::decay_t>; + return exp.has_value() + ? result() + : result(unexpect, detail::invoke(std::forward(f), + std::forward(exp).error())); +} +template >::value> * = nullptr, + class Ret = decltype(detail::invoke(std::declval(), + std::declval().error())), + detail::enable_if_t::value> * = nullptr> +auto map_error_impl(Exp &&exp, F &&f) { + using result = expected, monostate>; + if (exp.has_value()) { + return result(); + } + + detail::invoke(std::forward(f), std::forward(exp).error()); + return result(unexpect, monostate{}); +} +#else +template >::value> * = nullptr, + class Ret = decltype(detail::invoke(std::declval(), + std::declval().error())), + detail::enable_if_t::value> * = nullptr> +constexpr auto map_error_impl(Exp &&exp, F &&f) + -> expected, detail::decay_t> { + using result = expected, detail::decay_t>; + + return exp.has_value() + ? result(*std::forward(exp)) + : result(unexpect, detail::invoke(std::forward(f), + std::forward(exp).error())); +} + +template >::value> * = nullptr, + class Ret = decltype(detail::invoke(std::declval(), + std::declval().error())), + detail::enable_if_t::value> * = nullptr> +auto map_error_impl(Exp &&exp, F &&f) -> expected, monostate> { + using result = expected, monostate>; + if (exp.has_value()) { + return result(*std::forward(exp)); + } + + detail::invoke(std::forward(f), std::forward(exp).error()); + return result(unexpect, monostate{}); +} + +template >::value> * = nullptr, + class Ret = decltype(detail::invoke(std::declval(), + std::declval().error())), + detail::enable_if_t::value> * = nullptr> +constexpr auto map_error_impl(Exp &&exp, F &&f) + -> expected, detail::decay_t> { + using result = expected, detail::decay_t>; + + return exp.has_value() + ? result() + : result(unexpect, detail::invoke(std::forward(f), + std::forward(exp).error())); +} + +template >::value> * = nullptr, + class Ret = decltype(detail::invoke(std::declval(), + std::declval().error())), + detail::enable_if_t::value> * = nullptr> +auto map_error_impl(Exp &&exp, F &&f) -> expected, monostate> { + using result = expected, monostate>; + if (exp.has_value()) { + return result(); + } + + detail::invoke(std::forward(f), std::forward(exp).error()); + return result(unexpect, monostate{}); +} +#endif + +#ifdef TL_EXPECTED_CXX14 +template (), + std::declval().error())), + detail::enable_if_t::value> * = nullptr> +constexpr auto or_else_impl(Exp &&exp, F &&f) { + static_assert(detail::is_expected::value, "F must return an expected"); + return exp.has_value() ? std::forward(exp) + : detail::invoke(std::forward(f), + std::forward(exp).error()); +} + +template (), + std::declval().error())), + detail::enable_if_t::value> * = nullptr> +detail::decay_t or_else_impl(Exp &&exp, F &&f) { + return exp.has_value() ? std::forward(exp) + : (detail::invoke(std::forward(f), + std::forward(exp).error()), + std::forward(exp)); +} +#else +template (), + std::declval().error())), + detail::enable_if_t::value> * = nullptr> +auto or_else_impl(Exp &&exp, F &&f) -> Ret { + static_assert(detail::is_expected::value, "F must return an expected"); + return exp.has_value() ? std::forward(exp) + : detail::invoke(std::forward(f), + std::forward(exp).error()); +} + +template (), + std::declval().error())), + detail::enable_if_t::value> * = nullptr> +detail::decay_t or_else_impl(Exp &&exp, F &&f) { + return exp.has_value() ? std::forward(exp) + : (detail::invoke(std::forward(f), + std::forward(exp).error()), + std::forward(exp)); +} +#endif +} // namespace detail + +template +constexpr bool operator==(const expected &lhs, + const expected &rhs) { + return (lhs.has_value() != rhs.has_value()) + ? false + : (!lhs.has_value() ? lhs.error() == rhs.error() : *lhs == *rhs); +} +template +constexpr bool operator!=(const expected &lhs, + const expected &rhs) { + return (lhs.has_value() != rhs.has_value()) + ? true + : (!lhs.has_value() ? lhs.error() != rhs.error() : *lhs != *rhs); +} +template +constexpr bool operator==(const expected &lhs, + const expected &rhs) { + return (lhs.has_value() != rhs.has_value()) + ? false + : (!lhs.has_value() ? lhs.error() == rhs.error() : true); +} +template +constexpr bool operator!=(const expected &lhs, + const expected &rhs) { + return (lhs.has_value() != rhs.has_value()) + ? true + : (!lhs.has_value() ? lhs.error() != rhs.error() : false); +} + +template +constexpr bool operator==(const expected &x, const U &v) { + return x.has_value() ? *x == v : false; +} +template +constexpr bool operator==(const U &v, const expected &x) { + return x.has_value() ? *x == v : false; +} +template +constexpr bool operator!=(const expected &x, const U &v) { + return x.has_value() ? *x != v : true; +} +template +constexpr bool operator!=(const U &v, const expected &x) { + return x.has_value() ? *x != v : true; +} + +template +constexpr bool operator==(const expected &x, const unexpected &e) { + return x.has_value() ? false : x.error() == e.value(); +} +template +constexpr bool operator==(const unexpected &e, const expected &x) { + return x.has_value() ? false : x.error() == e.value(); +} +template +constexpr bool operator!=(const expected &x, const unexpected &e) { + return x.has_value() ? true : x.error() != e.value(); +} +template +constexpr bool operator!=(const unexpected &e, const expected &x) { + return x.has_value() ? true : x.error() != e.value(); +} + +template ::value || + std::is_move_constructible::value) && + detail::is_swappable::value && + std::is_move_constructible::value && + detail::is_swappable::value> * = nullptr> +void swap(expected &lhs, + expected &rhs) noexcept(noexcept(lhs.swap(rhs))) { + lhs.swap(rhs); +} +} // namespace tl + +#endif diff --git a/src/baseclient.cc b/src/baseclient.cc index afac5dc..78e38fe 100644 --- a/src/baseclient.cc +++ b/src/baseclient.cc @@ -130,98 +130,84 @@ void BaseClient::HandleRedirectResponse(std::string& code, std::string& message, } } -Response BaseClient::GetErrorResponse(http::Response resp, - std::string_view resource, - http::Method method, - const std::string& bucket_name, - const std::string& object_name) { +Result BaseClient::GetErrorResponse(http::Response resp, + std::string_view resource, + http::Method method, + const std::string& bucket_name, + const std::string& object_name) { if (!resp.error.empty()) { - return error::make(resp.error); + return tl::make_unexpected(error::Error(resp.error)); } if (!resp.body.empty()) { std::list values = resp.headers.Get("Content-Type"); for (auto& value : values) { if (utils::Contains(utils::ToLower(value), "application/xml")) { - return Response::ParseXML(resp.body, resp.status_code, resp.headers); + auto parsed = + Response::ParseXML(resp.body, resp.status_code, resp.headers); + if (!parsed) { + return tl::make_unexpected(parsed.error()); + } + return tl::make_unexpected( + error::Error(parsed->code + ": " + parsed->message)); } } - auto response = - error::make("invalid response received; status code: " + - std::to_string(resp.status_code) + - "; content-type: " + utils::Join(values, ",")); - response.status_code = resp.status_code; - response.headers = resp.headers; - return response; + return error::make("invalid response received; status code: " + + std::to_string(resp.status_code) + + "; content-type: " + utils::Join(values, ",")); } - Response response; - response.status_code = resp.status_code; - response.headers = resp.headers; - + // Format the error message based on status code. switch (resp.status_code) { case 301: case 307: - case 400: - HandleRedirectResponse(response.code, response.message, resp.status_code, - method, resp.headers, bucket_name, true); - break; + case 400: { + std::string code; + std::string message; + HandleRedirectResponse(code, message, resp.status_code, method, + resp.headers, bucket_name, true); + if (code == "RetryHead") { + return tl::make_unexpected(error::Error("RetryHead")); + } + return tl::make_unexpected(error::Error(code + ": " + message)); + } case 403: - response.code = "AccessDenied"; - response.message = "Access denied"; - break; + return tl::make_unexpected(error::Error("AccessDenied: Access denied")); case 404: if (!object_name.empty()) { - response.code = "NoSuchKey"; - response.message = "Object does not exist"; + return tl::make_unexpected( + error::Error("NoSuchKey: Object does not exist")); } else if (bucket_name.empty()) { - response.code = "NoSuchBucket"; - response.message = "Bucket does not exist"; + return tl::make_unexpected( + error::Error("NoSuchBucket: Bucket does not exist")); } else { - response.code = "ResourceNotFound"; - response.message = "Request resource not found"; + return tl::make_unexpected( + error::Error("ResourceNotFound: Request resource not found")); } - break; case 405: - response.code = "MethodNotAllowed"; - response.message = - "The specified method is not allowed against this resource"; - break; + return tl::make_unexpected(error::Error( + "MethodNotAllowed: The specified method is not allowed against " + "this resource")); case 409: if (bucket_name.empty()) { - response.code = "NoSuchBucket"; - response.message = "Bucket does not exist"; + return tl::make_unexpected( + error::Error("NoSuchBucket: Bucket does not exist")); } else { - response.code = "ResourceConflict"; - response.message = "Request resource conflicts"; + return tl::make_unexpected( + error::Error("ResourceConflict: Request resource conflicts")); } - break; case 501: - response.code = "MethodNotAllowed"; - response.message = - "The specified method is not allowed against this resource"; - break; - default: { - auto response = - error::make("server failed with HTTP status code " + - std::to_string(resp.status_code)); - response.status_code = resp.status_code; - response.headers = resp.headers; - return response; - } + return tl::make_unexpected(error::Error( + "MethodNotAllowed: The specified method is not allowed against " + "this resource")); + default: + return error::make("server failed with HTTP status code " + + std::to_string(resp.status_code)); } - - response.resource = resource; - response.request_id = response.headers.GetFront("x-amz-request-id"); - response.host_id = response.headers.GetFront("x-amz-id-2"); - response.bucket_name = bucket_name; - response.object_name = object_name; - - return response; } -Response BaseClient::execute(Request& req) { +Result BaseClient::execute(Request& req) { req.user_agent = user_agent_; req.ignore_cert_check = ignore_cert_check_; if (!ssl_cert_file_.empty()) req.ssl_cert_file = ssl_cert_file_; @@ -236,36 +222,34 @@ Response BaseClient::execute(Request& req) { return resp; } - Response resp = GetErrorResponse(response, request.url.path, req.method, - req.bucket_name, req.object_name); - if (resp.code == "NoSuchBucket" || resp.code == "RetryHead") { - std::unique_lock lock(region_map_mutex_); - region_map_.erase(req.bucket_name); + auto err = GetErrorResponse(response, request.url.path, req.method, + req.bucket_name, req.object_name); + if (!err) { + std::string err_str = err.error().String(); + if (err_str.find("NoSuchBucket") != std::string::npos || + err_str == "RetryHead") { + std::unique_lock lock(region_map_mutex_); + region_map_.erase(req.bucket_name); + } } - - return resp; + return err; } -Response BaseClient::Execute(Request& req) { - Response resp = execute(req); - if (resp || resp.code != "RetryHead") return resp; +Result BaseClient::Execute(Request& req) { + auto exec_resp = execute(req); + if (exec_resp) return exec_resp; + if (exec_resp.error().String() != "RetryHead") return exec_resp; // Retry only once on RetryHead error. - resp = execute(req); - if (resp || resp.code != "RetryHead") return resp; - - std::string code; - std::string message; - HandleRedirectResponse(code, message, resp.status_code, req.method, - resp.headers, req.bucket_name); - resp.code = code; - resp.message = message; + exec_resp = execute(req); + if (exec_resp) return exec_resp; + if (exec_resp.error().String() != "RetryHead") return exec_resp; - return resp; + return tl::make_unexpected(exec_resp.error()); } -GetRegionResponse BaseClient::GetRegion(const std::string& bucket_name, - const std::string& region) { +Result BaseClient::GetRegion(const std::string& bucket_name, + const std::string& region) { std::string base_region = base_url_.region; if (!region.empty()) { if (!base_region.empty() && base_region != region) { @@ -296,13 +280,13 @@ GetRegionResponse BaseClient::GetRegion(const std::string& bucket_name, req.query_params.Add("location", ""); req.bucket_name = bucket_name; - Response resp = Execute(req); - if (!resp) { - return GetRegionResponse(resp); + auto exec_gr = Execute(req); + if (!exec_gr) { + return tl::make_unexpected(exec_gr.error()); } pugi::xml_document xdoc; - pugi::xml_parse_result result = xdoc.load_string(resp.data.data()); + pugi::xml_parse_result result = xdoc.load_string(exec_gr->data.data()); if (!result) { return error::make("unable to parse XML"); } @@ -323,17 +307,18 @@ GetRegionResponse BaseClient::GetRegion(const std::string& bucket_name, return GetRegionResponse(value); } -AbortMultipartUploadResponse BaseClient::AbortMultipartUpload( +Result BaseClient::AbortMultipartUpload( AbortMultipartUploadArgs args) { if (error::Error err = args.Validate()) { - return AbortMultipartUploadResponse(err); + return tl::make_unexpected(err); } std::string region; - if (GetRegionResponse resp = GetRegion(args.bucket, args.region)) { - region = resp.region; + auto get_resp = GetRegion(args.bucket, args.region); + if (get_resp) { + region = get_resp->region; } else { - return AbortMultipartUploadResponse(resp); + return tl::make_unexpected(get_resp.error()); } Request req(http::Method::kDelete, region, base_url_, args.extra_headers, @@ -342,43 +327,47 @@ AbortMultipartUploadResponse BaseClient::AbortMultipartUpload( req.object_name = args.object; req.query_params.Add("uploadId", args.upload_id); - return AbortMultipartUploadResponse(Execute(req)); + auto exec_abort = Execute(req); + if (!exec_abort) return tl::make_unexpected(exec_abort.error()); + return AbortMultipartUploadResponse(std::move(*exec_abort)); } -BucketExistsResponse BaseClient::BucketExists(BucketExistsArgs args) { +Result BaseClient::BucketExists(BucketExistsArgs args) { if (error::Error err = args.Validate()) { - return BucketExistsResponse(err); + return tl::make_unexpected(err); } std::string region; - if (GetRegionResponse resp = GetRegion(args.bucket, args.region)) { - region = resp.region; + auto get_resp = GetRegion(args.bucket, args.region); + if (get_resp) { + region = get_resp->region; } else { - return (resp.code == "NoSuchBucket") ? BucketExistsResponse(false) - : BucketExistsResponse(resp); + if (get_resp.error().String().find("NoSuchBucket") != std::string::npos) + return BucketExistsResponse(false); + return tl::make_unexpected(get_resp.error()); } Request req(http::Method::kHead, region, base_url_, args.extra_headers, args.extra_query_params); req.bucket_name = args.bucket; - if (Response resp = Execute(req)) { + auto bucket_exec = Execute(req); + if (bucket_exec) { return BucketExistsResponse(true); - } else { - return (resp.code == "NoSuchBucket") ? BucketExistsResponse(false) - : BucketExistsResponse(resp); } + return tl::make_unexpected(bucket_exec.error()); } -CompleteMultipartUploadResponse BaseClient::CompleteMultipartUpload( +Result BaseClient::CompleteMultipartUpload( CompleteMultipartUploadArgs args) { if (error::Error err = args.Validate()) { - return CompleteMultipartUploadResponse(err); + return tl::make_unexpected(err); } std::string region; - if (GetRegionResponse resp = GetRegion(args.bucket, args.region)) { - region = resp.region; + auto get_resp = GetRegion(args.bucket, args.region); + if (get_resp) { + region = get_resp->region; } else { - return CompleteMultipartUploadResponse(resp); + return tl::make_unexpected(get_resp.error()); } Request req(http::Method::kPost, region, base_url_, args.extra_headers, @@ -407,18 +396,18 @@ CompleteMultipartUploadResponse BaseClient::CompleteMultipartUpload( headers.Add("Content-MD5", utils::Md5sumHash(body)); req.headers = headers; - Response response = Execute(req); + auto response = Execute(req); if (!response) { - return CompleteMultipartUploadResponse(response); + return tl::make_unexpected(response.error()); } return CompleteMultipartUploadResponse::ParseXML( - response.data, response.headers.GetFront("x-amz-version-id")); + response->data, response->headers.GetFront("x-amz-version-id")); } -CreateMultipartUploadResponse BaseClient::CreateMultipartUpload( +Result BaseClient::CreateMultipartUpload( CreateMultipartUploadArgs args) { if (error::Error err = args.Validate()) { - return CreateMultipartUploadResponse(err); + return tl::make_unexpected(err); } if (!args.headers.Contains("Content-Type")) { @@ -426,10 +415,11 @@ CreateMultipartUploadResponse BaseClient::CreateMultipartUpload( } std::string region; - if (GetRegionResponse resp = GetRegion(args.bucket, args.region)) { - region = resp.region; + auto get_resp = GetRegion(args.bucket, args.region); + if (get_resp) { + region = get_resp->region; } else { - return CreateMultipartUploadResponse(resp); + return tl::make_unexpected(get_resp.error()); } Request req(http::Method::kPost, region, base_url_, args.extra_headers, @@ -439,9 +429,9 @@ CreateMultipartUploadResponse BaseClient::CreateMultipartUpload( req.query_params.Add("uploads", ""); req.headers.AddAll(args.headers); - if (Response resp = Execute(req)) { + if (auto resp = Execute(req)) { pugi::xml_document xdoc; - pugi::xml_parse_result result = xdoc.load_string(resp.data.data()); + pugi::xml_parse_result result = xdoc.load_string(resp->data.data()); if (!result) { return error::make("unable to parse XML"); } @@ -449,21 +439,22 @@ CreateMultipartUploadResponse BaseClient::CreateMultipartUpload( xdoc.select_node("/InitiateMultipartUploadResult/UploadId/text()"); return CreateMultipartUploadResponse(std::string(text.node().value())); } else { - return CreateMultipartUploadResponse(resp); + return tl::make_unexpected(resp.error()); } } -DeleteBucketEncryptionResponse BaseClient::DeleteBucketEncryption( +Result BaseClient::DeleteBucketEncryption( DeleteBucketEncryptionArgs args) { if (error::Error err = args.Validate()) { - return DeleteBucketEncryptionResponse(err); + return tl::make_unexpected(err); } std::string region; - if (GetRegionResponse resp = GetRegion(args.bucket, args.region)) { - region = resp.region; + auto get_resp = GetRegion(args.bucket, args.region); + if (get_resp) { + region = get_resp->region; } else { - return DeleteBucketEncryptionResponse(resp); + return tl::make_unexpected(get_resp.error()); } Request req(http::Method::kDelete, region, base_url_, args.extra_headers, @@ -471,26 +462,23 @@ DeleteBucketEncryptionResponse BaseClient::DeleteBucketEncryption( req.bucket_name = args.bucket; req.query_params.Add("encryption", ""); - Response resp = Execute(req); - if (resp) { - return DeleteBucketEncryptionResponse(resp); - } - if (resp.code != "ServerSideEncryptionConfigurationNotFoundError") { - return DeleteBucketEncryptionResponse(resp); - } - return DeleteBucketEncryptionResponse(); + auto enc_resp = Execute(req); + if (!enc_resp) + return DeleteBucketEncryptionResponse(); // no encryption found + return DeleteBucketEncryptionResponse(std::move(*enc_resp)); } -DisableObjectLegalHoldResponse BaseClient::DisableObjectLegalHold( +Result BaseClient::DisableObjectLegalHold( DisableObjectLegalHoldArgs args) { if (error::Error err = args.Validate()) { - return DisableObjectLegalHoldResponse(err); + return tl::make_unexpected(err); } std::string region; - if (GetRegionResponse resp = GetRegion(args.bucket, args.region)) { - region = resp.region; + auto get_resp = GetRegion(args.bucket, args.region); + if (get_resp) { + region = get_resp->region; } else { - return DisableObjectLegalHoldResponse(resp); + return tl::make_unexpected(get_resp.error()); } std::string body = "OFF"; @@ -506,20 +494,23 @@ DisableObjectLegalHoldResponse BaseClient::DisableObjectLegalHold( req.headers.Add("Content-MD5", utils::Md5sumHash(body)); req.body = std::move(body); - return DisableObjectLegalHoldResponse(Execute(req)); + auto exec_disable = Execute(req); + if (!exec_disable) return tl::make_unexpected(exec_disable.error()); + return DisableObjectLegalHoldResponse(std::move(*exec_disable)); } -DeleteBucketLifecycleResponse BaseClient::DeleteBucketLifecycle( +Result BaseClient::DeleteBucketLifecycle( DeleteBucketLifecycleArgs args) { if (error::Error err = args.Validate()) { - return DeleteBucketLifecycleResponse(err); + return tl::make_unexpected(err); } std::string region; - if (GetRegionResponse resp = GetRegion(args.bucket, args.region)) { - region = resp.region; + auto get_resp = GetRegion(args.bucket, args.region); + if (get_resp) { + region = get_resp->region; } else { - return DeleteBucketLifecycleResponse(resp); + return tl::make_unexpected(get_resp.error()); } Request req(http::Method::kDelete, region, base_url_, args.extra_headers, @@ -527,13 +518,15 @@ DeleteBucketLifecycleResponse BaseClient::DeleteBucketLifecycle( req.bucket_name = args.bucket; req.query_params.Add("lifecycle", ""); - return DeleteBucketLifecycleResponse(Execute(req)); + auto exec_life = Execute(req); + if (!exec_life) return tl::make_unexpected(exec_life.error()); + return DeleteBucketLifecycleResponse(std::move(*exec_life)); } -DeleteBucketNotificationResponse BaseClient::DeleteBucketNotification( +Result BaseClient::DeleteBucketNotification( DeleteBucketNotificationArgs args) { if (error::Error err = args.Validate()) { - return DeleteBucketNotificationResponse(err); + return tl::make_unexpected(err); } NotificationConfig config; @@ -543,20 +536,23 @@ DeleteBucketNotificationResponse BaseClient::DeleteBucketNotification( sbnargs.bucket = args.bucket; sbnargs.region = args.region; - return DeleteBucketNotificationResponse(SetBucketNotification(sbnargs)); + auto notif_resp = SetBucketNotification(sbnargs); + if (!notif_resp) return tl::make_unexpected(notif_resp.error()); + return DeleteBucketNotificationResponse(std::move(*notif_resp)); } -DeleteBucketPolicyResponse BaseClient::DeleteBucketPolicy( +Result BaseClient::DeleteBucketPolicy( DeleteBucketPolicyArgs args) { if (error::Error err = args.Validate()) { - return DeleteBucketPolicyResponse(err); + return tl::make_unexpected(err); } std::string region; - if (GetRegionResponse resp = GetRegion(args.bucket, args.region)) { - region = resp.region; + auto get_resp = GetRegion(args.bucket, args.region); + if (get_resp) { + region = get_resp->region; } else { - return DeleteBucketPolicyResponse(resp); + return tl::make_unexpected(get_resp.error()); } Request req(http::Method::kDelete, region, base_url_, args.extra_headers, @@ -564,20 +560,23 @@ DeleteBucketPolicyResponse BaseClient::DeleteBucketPolicy( req.bucket_name = args.bucket; req.query_params.Add("policy", ""); - return DeleteBucketPolicyResponse(Execute(req)); + auto exec_set = Execute(req); + if (!exec_set) return tl::make_unexpected(exec_set.error()); + return DeleteBucketPolicyResponse(std::move(*exec_set)); } -DeleteBucketReplicationResponse BaseClient::DeleteBucketReplication( +Result BaseClient::DeleteBucketReplication( DeleteBucketReplicationArgs args) { if (error::Error err = args.Validate()) { - return DeleteBucketReplicationResponse(err); + return tl::make_unexpected(err); } std::string region; - if (GetRegionResponse resp = GetRegion(args.bucket, args.region)) { - region = resp.region; + auto get_resp = GetRegion(args.bucket, args.region); + if (get_resp) { + region = get_resp->region; } else { - return DeleteBucketReplicationResponse(resp); + return tl::make_unexpected(get_resp.error()); } Request req(http::Method::kDelete, region, base_url_, args.extra_headers, @@ -585,27 +584,29 @@ DeleteBucketReplicationResponse BaseClient::DeleteBucketReplication( req.bucket_name = args.bucket; req.query_params.Add("replication", ""); - Response resp = Execute(req); - if (resp) { - return DeleteBucketReplicationResponse(resp); - } - if (resp.code != "ReplicationConfigurationNotFoundError") { - return DeleteBucketReplicationResponse(resp); + auto resp = Execute(req); + if (!resp) { + if (resp.error().String().find("ReplicationConfigurationNotFoundError") == + std::string::npos) { + return tl::make_unexpected(resp.error()); + } + return DeleteBucketReplicationResponse(); } - return DeleteBucketReplicationResponse(); + return DeleteBucketReplicationResponse(std::move(*resp)); } -DeleteBucketTagsResponse BaseClient::DeleteBucketTags( +Result BaseClient::DeleteBucketTags( DeleteBucketTagsArgs args) { if (error::Error err = args.Validate()) { - return DeleteBucketTagsResponse(err); + return tl::make_unexpected(err); } std::string region; - if (GetRegionResponse resp = GetRegion(args.bucket, args.region)) { - region = resp.region; + auto get_resp = GetRegion(args.bucket, args.region); + if (get_resp) { + region = get_resp->region; } else { - return DeleteBucketTagsResponse(resp); + return tl::make_unexpected(get_resp.error()); } Request req(http::Method::kDelete, region, base_url_, args.extra_headers, @@ -613,20 +614,25 @@ DeleteBucketTagsResponse BaseClient::DeleteBucketTags( req.bucket_name = args.bucket; req.query_params.Add("tagging", ""); - return DeleteBucketTagsResponse(Execute(req)); + auto exec_set = Execute(req); + + if (!exec_set) return tl::make_unexpected(exec_set.error()); + + return DeleteBucketTagsResponse(std::move(*exec_set)); } -DeleteObjectLockConfigResponse BaseClient::DeleteObjectLockConfig( +Result BaseClient::DeleteObjectLockConfig( DeleteObjectLockConfigArgs args) { if (error::Error err = args.Validate()) { - return DeleteObjectLockConfigResponse(err); + return tl::make_unexpected(err); } std::string region; - if (GetRegionResponse resp = GetRegion(args.bucket, args.region)) { - region = resp.region; + auto get_resp = GetRegion(args.bucket, args.region); + if (get_resp) { + region = get_resp->region; } else { - return DeleteObjectLockConfigResponse(resp); + return tl::make_unexpected(get_resp.error()); } Request req(http::Method::kDelete, region, base_url_, args.extra_headers, @@ -634,20 +640,25 @@ DeleteObjectLockConfigResponse BaseClient::DeleteObjectLockConfig( req.bucket_name = args.bucket; req.query_params.Add("object-lock", ""); - return DeleteObjectLockConfigResponse(Execute(req)); + auto exec_set = Execute(req); + + if (!exec_set) return tl::make_unexpected(exec_set.error()); + + return DeleteObjectLockConfigResponse(std::move(*exec_set)); } -DeleteObjectTagsResponse BaseClient::DeleteObjectTags( +Result BaseClient::DeleteObjectTags( DeleteObjectTagsArgs args) { if (error::Error err = args.Validate()) { - return DeleteObjectTagsResponse(err); + return tl::make_unexpected(err); } std::string region; - if (GetRegionResponse resp = GetRegion(args.bucket, args.region)) { - region = resp.region; + auto get_resp = GetRegion(args.bucket, args.region); + if (get_resp) { + region = get_resp->region; } else { - return DeleteObjectTagsResponse(resp); + return tl::make_unexpected(get_resp.error()); } Request req(http::Method::kDelete, region, base_url_, args.extra_headers, @@ -659,20 +670,25 @@ DeleteObjectTagsResponse BaseClient::DeleteObjectTags( } req.query_params.Add("tagging", ""); - return DeleteObjectTagsResponse(Execute(req)); + auto exec_set = Execute(req); + + if (!exec_set) return tl::make_unexpected(exec_set.error()); + + return DeleteObjectTagsResponse(std::move(*exec_set)); } -EnableObjectLegalHoldResponse BaseClient::EnableObjectLegalHold( +Result BaseClient::EnableObjectLegalHold( EnableObjectLegalHoldArgs args) { if (error::Error err = args.Validate()) { - return EnableObjectLegalHoldResponse(err); + return tl::make_unexpected(err); } std::string region; - if (GetRegionResponse resp = GetRegion(args.bucket, args.region)) { - region = resp.region; + auto get_resp = GetRegion(args.bucket, args.region); + if (get_resp) { + region = get_resp->region; } else { - return EnableObjectLegalHoldResponse(resp); + return tl::make_unexpected(get_resp.error()); } std::string body = "ON"; @@ -688,20 +704,25 @@ EnableObjectLegalHoldResponse BaseClient::EnableObjectLegalHold( req.headers.Add("Content-MD5", utils::Md5sumHash(body)); req.body = std::move(body); - return EnableObjectLegalHoldResponse(Execute(req)); + auto exec_set = Execute(req); + + if (!exec_set) return tl::make_unexpected(exec_set.error()); + + return EnableObjectLegalHoldResponse(std::move(*exec_set)); } -GetBucketEncryptionResponse BaseClient::GetBucketEncryption( +Result BaseClient::GetBucketEncryption( GetBucketEncryptionArgs args) { if (error::Error err = args.Validate()) { - return GetBucketEncryptionResponse(err); + return tl::make_unexpected(err); } std::string region; - if (GetRegionResponse resp = GetRegion(args.bucket, args.region)) { - region = resp.region; + auto get_resp = GetRegion(args.bucket, args.region); + if (get_resp) { + region = get_resp->region; } else { - return GetBucketEncryptionResponse(resp); + return tl::make_unexpected(get_resp.error()); } Request req(http::Method::kGet, region, base_url_, args.extra_headers, @@ -709,24 +730,25 @@ GetBucketEncryptionResponse BaseClient::GetBucketEncryption( req.bucket_name = args.bucket; req.query_params.Add("encryption", ""); - Response resp = Execute(req); + auto resp = Execute(req); if (resp) { - return GetBucketEncryptionResponse::ParseXML(resp.data); + return GetBucketEncryptionResponse::ParseXML(resp->data); } - return GetBucketEncryptionResponse(resp); + return tl::make_unexpected(resp.error()); } -GetBucketLifecycleResponse BaseClient::GetBucketLifecycle( +Result BaseClient::GetBucketLifecycle( GetBucketLifecycleArgs args) { if (error::Error err = args.Validate()) { - return GetBucketLifecycleResponse(err); + return tl::make_unexpected(err); } std::string region; - if (GetRegionResponse resp = GetRegion(args.bucket, args.region)) { - region = resp.region; + auto get_resp = GetRegion(args.bucket, args.region); + if (get_resp) { + region = get_resp->region; } else { - return GetBucketLifecycleResponse(resp); + return tl::make_unexpected(get_resp.error()); } Request req(http::Method::kGet, region, base_url_, args.extra_headers, @@ -734,29 +756,31 @@ GetBucketLifecycleResponse BaseClient::GetBucketLifecycle( req.bucket_name = args.bucket; req.query_params.Add("lifecycle", ""); - Response resp = Execute(req); + auto resp = Execute(req); if (!resp) { - if (resp.code == "NoSuchLifecycleConfiguration") { + if (resp.error().String().find("NoSuchLifecycleConfiguration") != + std::string::npos) { return GetBucketLifecycleResponse(LifecycleConfig()); } - return GetBucketLifecycleResponse(resp); + return tl::make_unexpected(resp.error()); } - return GetBucketLifecycleResponse::ParseXML(resp.data); + return GetBucketLifecycleResponse::ParseXML(resp->data); } -GetBucketNotificationResponse BaseClient::GetBucketNotification( +Result BaseClient::GetBucketNotification( GetBucketNotificationArgs args) { if (error::Error err = args.Validate()) { - return GetBucketNotificationResponse(err); + return tl::make_unexpected(err); } std::string region; - if (GetRegionResponse resp = GetRegion(args.bucket, args.region)) { - region = resp.region; + auto get_resp = GetRegion(args.bucket, args.region); + if (get_resp) { + region = get_resp->region; } else { - return GetBucketNotificationResponse(resp); + return tl::make_unexpected(get_resp.error()); } Request req(http::Method::kGet, region, base_url_, args.extra_headers, @@ -764,23 +788,25 @@ GetBucketNotificationResponse BaseClient::GetBucketNotification( req.bucket_name = args.bucket; req.query_params.Add("notification", ""); - Response resp = Execute(req); + auto resp = Execute(req); if (resp) { - return GetBucketNotificationResponse::ParseXML(resp.data); + return GetBucketNotificationResponse::ParseXML(resp->data); } - return GetBucketNotificationResponse(resp); + return tl::make_unexpected(resp.error()); } -GetBucketPolicyResponse BaseClient::GetBucketPolicy(GetBucketPolicyArgs args) { +Result BaseClient::GetBucketPolicy( + GetBucketPolicyArgs args) { if (error::Error err = args.Validate()) { - return GetBucketPolicyResponse(err); + return tl::make_unexpected(err); } std::string region; - if (GetRegionResponse resp = GetRegion(args.bucket, args.region)) { - region = resp.region; + auto get_resp = GetRegion(args.bucket, args.region); + if (get_resp) { + region = get_resp->region; } else { - return GetBucketPolicyResponse(resp); + return tl::make_unexpected(get_resp.error()); } Request req(http::Method::kGet, region, base_url_, args.extra_headers, @@ -788,24 +814,25 @@ GetBucketPolicyResponse BaseClient::GetBucketPolicy(GetBucketPolicyArgs args) { req.bucket_name = args.bucket; req.query_params.Add("policy", ""); - Response resp = Execute(req); + auto resp = Execute(req); if (resp) { - return GetBucketPolicyResponse(resp.data); + return GetBucketPolicyResponse(resp->data); } - return GetBucketPolicyResponse(resp); + return tl::make_unexpected(resp.error()); } -GetBucketReplicationResponse BaseClient::GetBucketReplication( +Result BaseClient::GetBucketReplication( GetBucketReplicationArgs args) { if (error::Error err = args.Validate()) { - return GetBucketReplicationResponse(err); + return tl::make_unexpected(err); } std::string region; - if (GetRegionResponse resp = GetRegion(args.bucket, args.region)) { - region = resp.region; + auto get_resp = GetRegion(args.bucket, args.region); + if (get_resp) { + region = get_resp->region; } else { - return GetBucketReplicationResponse(resp); + return tl::make_unexpected(get_resp.error()); } Request req(http::Method::kGet, region, base_url_, args.extra_headers, @@ -813,23 +840,25 @@ GetBucketReplicationResponse BaseClient::GetBucketReplication( req.bucket_name = args.bucket; req.query_params.Add("replication", ""); - Response resp = Execute(req); + auto resp = Execute(req); if (resp) { - return GetBucketReplicationResponse::ParseXML(resp.data); + return GetBucketReplicationResponse::ParseXML(resp->data); } - return GetBucketReplicationResponse(resp); + return tl::make_unexpected(resp.error()); } -GetBucketTagsResponse BaseClient::GetBucketTags(GetBucketTagsArgs args) { +Result BaseClient::GetBucketTags( + GetBucketTagsArgs args) { if (error::Error err = args.Validate()) { - return GetBucketTagsResponse(err); + return tl::make_unexpected(err); } std::string region; - if (GetRegionResponse resp = GetRegion(args.bucket, args.region)) { - region = resp.region; + auto get_resp = GetRegion(args.bucket, args.region); + if (get_resp) { + region = get_resp->region; } else { - return GetBucketTagsResponse(resp); + return tl::make_unexpected(get_resp.error()); } Request req(http::Method::kGet, region, base_url_, args.extra_headers, @@ -837,24 +866,25 @@ GetBucketTagsResponse BaseClient::GetBucketTags(GetBucketTagsArgs args) { req.bucket_name = args.bucket; req.query_params.Add("tagging", ""); - Response resp = Execute(req); + auto resp = Execute(req); if (resp) { - return GetBucketTagsResponse::ParseXML(resp.data); + return GetBucketTagsResponse::ParseXML(resp->data); } - return GetBucketTagsResponse(resp); + return tl::make_unexpected(resp.error()); } -GetBucketVersioningResponse BaseClient::GetBucketVersioning( +Result BaseClient::GetBucketVersioning( GetBucketVersioningArgs args) { if (error::Error err = args.Validate()) { - return GetBucketVersioningResponse(err); + return tl::make_unexpected(err); } std::string region; - if (GetRegionResponse resp = GetRegion(args.bucket, args.region)) { - region = resp.region; + auto get_resp = GetRegion(args.bucket, args.region); + if (get_resp) { + region = get_resp->region; } else { - return GetBucketVersioningResponse(resp); + return tl::make_unexpected(get_resp.error()); } Request req(http::Method::kGet, region, base_url_, args.extra_headers, @@ -862,14 +892,14 @@ GetBucketVersioningResponse BaseClient::GetBucketVersioning( req.bucket_name = args.bucket; req.query_params.Add("versioning", ""); - Response resp = Execute(req); + auto resp = Execute(req); if (!resp) { - return GetBucketVersioningResponse(resp); + return tl::make_unexpected(resp.error()); } GetBucketVersioningResponse response; pugi::xml_document xdoc; - pugi::xml_parse_result result = xdoc.load_string(resp.data.data()); + pugi::xml_parse_result result = xdoc.load_string(resp->data.data()); if (!result) { return error::make("unable to parse XML"); } @@ -887,12 +917,12 @@ GetBucketVersioningResponse BaseClient::GetBucketVersioning( response.mfa_delete = (strcmp(text.node().value(), "Enabled") == 0); } - return GetBucketVersioningResponse(response); + return response; } -GetObjectResponse BaseClient::GetObject(GetObjectArgs args) { +Result BaseClient::GetObject(GetObjectArgs args) { if (error::Error err = args.Validate()) { - return GetObjectResponse(err); + return tl::make_unexpected(err); } if (args.ssec != nullptr && !base_url_.https) { @@ -901,10 +931,11 @@ GetObjectResponse BaseClient::GetObject(GetObjectArgs args) { } std::string region; - if (GetRegionResponse resp = GetRegion(args.bucket, args.region)) { - region = resp.region; + auto get_resp = GetRegion(args.bucket, args.region); + if (get_resp) { + region = get_resp->region; } else { - return GetObjectResponse(resp); + return tl::make_unexpected(get_resp.error()); } Request req(http::Method::kGet, region, base_url_, args.extra_headers, @@ -920,20 +951,25 @@ GetObjectResponse BaseClient::GetObject(GetObjectArgs args) { req.progress_userdata = args.progress_userdata; req.headers.AddAll(args.Headers()); - return GetObjectResponse(Execute(req)); + auto exec_set = Execute(req); + + if (!exec_set) return tl::make_unexpected(exec_set.error()); + + return GetObjectResponse(std::move(*exec_set)); } -GetObjectLockConfigResponse BaseClient::GetObjectLockConfig( +Result BaseClient::GetObjectLockConfig( GetObjectLockConfigArgs args) { if (error::Error err = args.Validate()) { - return GetObjectLockConfigResponse(err); + return tl::make_unexpected(err); } std::string region; - if (GetRegionResponse resp = GetRegion(args.bucket, args.region)) { - region = resp.region; + auto get_resp = GetRegion(args.bucket, args.region); + if (get_resp) { + region = get_resp->region; } else { - return GetObjectLockConfigResponse(resp); + return tl::make_unexpected(get_resp.error()); } Request req(http::Method::kGet, region, base_url_, args.extra_headers, @@ -941,12 +977,12 @@ GetObjectLockConfigResponse BaseClient::GetObjectLockConfig( req.bucket_name = args.bucket; req.query_params.Add("object-lock", ""); - Response resp = Execute(req); + auto resp = Execute(req); if (!resp) { - return GetObjectLockConfigResponse(resp); + return tl::make_unexpected(resp.error()); } pugi::xml_document xdoc; - pugi::xml_parse_result result = xdoc.load_string(resp.data.data()); + pugi::xml_parse_result result = xdoc.load_string(resp->data.data()); if (!result) { return error::make("unable to parse XML"); } @@ -974,17 +1010,18 @@ GetObjectLockConfigResponse BaseClient::GetObjectLockConfig( return GetObjectLockConfigResponse(config); } -GetObjectRetentionResponse BaseClient::GetObjectRetention( +Result BaseClient::GetObjectRetention( GetObjectRetentionArgs args) { if (error::Error err = args.Validate()) { - return GetObjectRetentionResponse(err); + return tl::make_unexpected(err); } std::string region; - if (GetRegionResponse resp = GetRegion(args.bucket, args.region)) { - region = resp.region; + auto get_resp = GetRegion(args.bucket, args.region); + if (get_resp) { + region = get_resp->region; } else { - return GetObjectRetentionResponse(resp); + return tl::make_unexpected(get_resp.error()); } Request req(http::Method::kGet, region, base_url_, args.extra_headers, @@ -998,16 +1035,17 @@ GetObjectRetentionResponse BaseClient::GetObjectRetention( GetObjectRetentionResponse response; - Response resp = Execute(req); + auto resp = Execute(req); if (!resp) { - if (resp.code == "NoSuchObjectLockConfiguration") { - return GetObjectRetentionResponse(response); + if (resp.error().String().find("NoSuchObjectLockConfiguration") != + std::string::npos) { + return response; } - return GetObjectRetentionResponse(resp); + return tl::make_unexpected(resp.error()); } pugi::xml_document xdoc; - pugi::xml_parse_result result = xdoc.load_string(resp.data.data()); + pugi::xml_parse_result result = xdoc.load_string(resp->data.data()); if (!result) { return error::make("unable to parse XML"); } @@ -1019,19 +1057,21 @@ GetObjectRetentionResponse BaseClient::GetObjectRetention( response.retain_until_date = utils::UtcTime::FromISO8601UTC(text.node().value()); - return GetObjectRetentionResponse(response); + return response; } -GetObjectTagsResponse BaseClient::GetObjectTags(GetObjectTagsArgs args) { +Result BaseClient::GetObjectTags( + GetObjectTagsArgs args) { if (error::Error err = args.Validate()) { - return GetObjectTagsResponse(err); + return tl::make_unexpected(err); } std::string region; - if (GetRegionResponse resp = GetRegion(args.bucket, args.region)) { - region = resp.region; + auto get_resp = GetRegion(args.bucket, args.region); + if (get_resp) { + region = get_resp->region; } else { - return GetObjectTagsResponse(resp); + return tl::make_unexpected(get_resp.error()); } Request req(http::Method::kGet, region, base_url_, args.extra_headers, @@ -1043,24 +1083,25 @@ GetObjectTagsResponse BaseClient::GetObjectTags(GetObjectTagsArgs args) { } req.query_params.Add("tagging", ""); - Response resp = Execute(req); + auto resp = Execute(req); if (resp) { - return GetObjectTagsResponse::ParseXML(resp.data); + return GetObjectTagsResponse::ParseXML(resp->data); } - return GetObjectTagsResponse(resp); + return tl::make_unexpected(resp.error()); } -GetPresignedObjectUrlResponse BaseClient::GetPresignedObjectUrl( +Result BaseClient::GetPresignedObjectUrl( GetPresignedObjectUrlArgs args) { if (error::Error err = args.Validate()) { - return GetPresignedObjectUrlResponse(err); + return tl::make_unexpected(err); } std::string region; - if (GetRegionResponse resp = GetRegion(args.bucket, args.region)) { - region = resp.region; + auto get_resp = GetRegion(args.bucket, args.region); + if (get_resp) { + region = get_resp->region; } else { - return GetPresignedObjectUrlResponse(resp); + return tl::make_unexpected(get_resp.error()); } utils::Multimap query_params; @@ -1094,23 +1135,23 @@ GetPresignedObjectUrlResponse BaseClient::GetPresignedObjectUrl( return GetPresignedObjectUrlResponse(url.String()); } -GetPresignedPostFormDataResponse BaseClient::GetPresignedPostFormData( +Result BaseClient::GetPresignedPostFormData( PostPolicy policy) { if (!policy) { - return error::make( - "valid policy must be provided"); + return tl::make_unexpected(error::Error("valid policy must be provided")); } if (provider_ == nullptr) { - return error::make( - "Anonymous access does not require pre-signed post form-data"); + return tl::make_unexpected(error::Error( + "Anonymous access does not require pre-signed post form-data")); } std::string region; - if (GetRegionResponse resp = GetRegion(policy.bucket, policy.region)) { - region = resp.region; + auto get_resp = GetRegion(policy.bucket, policy.region); + if (get_resp) { + region = get_resp->region; } else { - return GetPresignedPostFormDataResponse(resp); + return tl::make_unexpected(get_resp.error()); } creds::Credentials creds = provider_->Fetch(); @@ -1118,22 +1159,23 @@ GetPresignedPostFormDataResponse BaseClient::GetPresignedPostFormData( if (error::Error err = policy.FormData(data, creds.access_key, creds.secret_key, creds.session_token, region)) { - return GetPresignedPostFormDataResponse(err); + return tl::make_unexpected(err); } return GetPresignedPostFormDataResponse(data); } -IsObjectLegalHoldEnabledResponse BaseClient::IsObjectLegalHoldEnabled( +Result BaseClient::IsObjectLegalHoldEnabled( IsObjectLegalHoldEnabledArgs args) { if (error::Error err = args.Validate()) { - return IsObjectLegalHoldEnabledResponse(err); + return tl::make_unexpected(err); } std::string region; - if (GetRegionResponse resp = GetRegion(args.bucket, args.region)) { - region = resp.region; + auto get_resp = GetRegion(args.bucket, args.region); + if (get_resp) { + region = get_resp->region; } else { - return IsObjectLegalHoldEnabledResponse(resp); + return tl::make_unexpected(get_resp.error()); } Request req(http::Method::kGet, region, base_url_, args.extra_headers, @@ -1145,16 +1187,17 @@ IsObjectLegalHoldEnabledResponse BaseClient::IsObjectLegalHoldEnabled( } req.query_params.Add("legal-hold", ""); - Response resp = Execute(req); + auto resp = Execute(req); if (!resp) { - if (resp.code == "NoSuchObjectLockConfiguration") { + if (resp.error().String().find("NoSuchObjectLockConfiguration") != + std::string::npos) { return IsObjectLegalHoldEnabledResponse(false); } - return IsObjectLegalHoldEnabledResponse(resp); + return tl::make_unexpected(resp.error()); } pugi::xml_document xdoc; - pugi::xml_parse_result result = xdoc.load_string(resp.data.data()); + pugi::xml_parse_result result = xdoc.load_string(resp->data.data()); if (!result) { return error::make("unable to parse XML"); } @@ -1163,24 +1206,24 @@ IsObjectLegalHoldEnabledResponse BaseClient::IsObjectLegalHoldEnabled( return IsObjectLegalHoldEnabledResponse(value == "ON"); } -ListBucketsResponse BaseClient::ListBuckets(ListBucketsArgs args) { +Result BaseClient::ListBuckets(ListBucketsArgs args) { Request req(http::Method::kGet, base_url_.region, base_url_, args.extra_headers, args.extra_query_params); - Response resp = Execute(req); + auto resp = Execute(req); if (!resp) { - return ListBucketsResponse(resp); + return tl::make_unexpected(resp.error()); } - return ListBucketsResponse::ParseXML(resp.data); + return ListBucketsResponse::ParseXML(resp->data); } -ListBucketsResponse BaseClient::ListBuckets() { +Result BaseClient::ListBuckets() { return ListBuckets(ListBucketsArgs()); } -ListenBucketNotificationResponse BaseClient::ListenBucketNotification( +Result BaseClient::ListenBucketNotification( ListenBucketNotificationArgs args) { if (error::Error err = args.Validate()) { - return ListenBucketNotificationResponse(err); + return tl::make_unexpected(err); } if (!base_url_.aws_domain_suffix.empty()) { @@ -1189,10 +1232,11 @@ ListenBucketNotificationResponse BaseClient::ListenBucketNotification( } std::string region; - if (GetRegionResponse resp = GetRegion(args.bucket, args.region)) { - region = resp.region; + auto get_resp = GetRegion(args.bucket, args.region); + if (get_resp) { + region = get_resp->region; } else { - return ListenBucketNotificationResponse(resp); + return tl::make_unexpected(get_resp.error()); } Request req = Request(http::Method::kGet, region, base_url_, @@ -1238,19 +1282,24 @@ ListenBucketNotificationResponse BaseClient::ListenBucketNotification( } }; - return ListenBucketNotificationResponse(Execute(req)); + auto exec_set = Execute(req); + + if (!exec_set) return tl::make_unexpected(exec_set.error()); + + return ListenBucketNotificationResponse(std::move(*exec_set)); } -ListObjectsResponse BaseClient::ListObjectsV1(ListObjectsV1Args args) { +Result BaseClient::ListObjectsV1(ListObjectsV1Args args) { if (error::Error err = args.Validate()) { - return ListObjectsResponse(err); + return tl::make_unexpected(err); } std::string region; - if (GetRegionResponse resp = GetRegion(args.bucket, args.region)) { - region = resp.region; + auto get_resp = GetRegion(args.bucket, args.region); + if (get_resp) { + region = get_resp->region; } else { - return ListObjectsResponse(resp); + return tl::make_unexpected(get_resp.error()); } Request req(http::Method::kGet, region, base_url_, args.extra_headers, @@ -1261,23 +1310,24 @@ ListObjectsResponse BaseClient::ListObjectsV1(ListObjectsV1Args args) { if (!args.marker.empty()) { req.query_params.Add("marker", args.marker); } - Response resp = Execute(req); + auto resp = Execute(req); if (!resp) { - return ListObjectsResponse(resp); + return tl::make_unexpected(resp.error()); } - return ListObjectsResponse::ParseXML(resp.data, false); + return ListObjectsResponse::ParseXML(resp->data, false); } -ListObjectsResponse BaseClient::ListObjectsV2(ListObjectsV2Args args) { +Result BaseClient::ListObjectsV2(ListObjectsV2Args args) { if (error::Error err = args.Validate()) { - return ListObjectsResponse(err); + return tl::make_unexpected(err); } std::string region; - if (GetRegionResponse resp = GetRegion(args.bucket, args.region)) { - region = resp.region; + auto get_resp = GetRegion(args.bucket, args.region); + if (get_resp) { + region = get_resp->region; } else { - return ListObjectsResponse(resp); + return tl::make_unexpected(get_resp.error()); } Request req(http::Method::kGet, region, base_url_, args.extra_headers, @@ -1298,24 +1348,25 @@ ListObjectsResponse BaseClient::ListObjectsV2(ListObjectsV2Args args) { if (args.include_user_metadata) { req.query_params.Add("metadata", "true"); } - Response resp = Execute(req); + auto resp = Execute(req); if (!resp) { - return ListObjectsResponse(resp); + return tl::make_unexpected(resp.error()); } - return ListObjectsResponse::ParseXML(resp.data, false); + return ListObjectsResponse::ParseXML(resp->data, false); } -ListObjectsResponse BaseClient::ListObjectVersions( +Result BaseClient::ListObjectVersions( ListObjectVersionsArgs args) { if (error::Error err = args.Validate()) { - return ListObjectsResponse(err); + return tl::make_unexpected(err); } std::string region; - if (GetRegionResponse resp = GetRegion(args.bucket, args.region)) { - region = resp.region; + auto get_resp = GetRegion(args.bucket, args.region); + if (get_resp) { + region = get_resp->region; } else { - return ListObjectsResponse(resp); + return tl::make_unexpected(get_resp.error()); } Request req(http::Method::kGet, region, base_url_, args.extra_headers, @@ -1331,16 +1382,16 @@ ListObjectsResponse BaseClient::ListObjectVersions( req.query_params.Add("version-id-marker", args.version_id_marker); } - Response resp = Execute(req); + auto resp = Execute(req); if (!resp) { - return ListObjectsResponse(resp); + return tl::make_unexpected(resp.error()); } - return ListObjectsResponse::ParseXML(resp.data, true); + return ListObjectsResponse::ParseXML(resp->data, true); } -MakeBucketResponse BaseClient::MakeBucket(MakeBucketArgs args) { +Result BaseClient::MakeBucket(MakeBucketArgs args) { if (error::Error err = args.Validate()) { - return MakeBucketResponse(err); + return tl::make_unexpected(err); } std::string region = args.region; @@ -1372,24 +1423,26 @@ MakeBucketResponse BaseClient::MakeBucket(MakeBucketArgs args) { req.body = body; } - Response resp = Execute(req); + auto resp = Execute(req); if (resp) { std::unique_lock lock(region_map_mutex_); region_map_[args.bucket] = region; + return MakeBucketResponse(std::move(*resp)); } - return MakeBucketResponse(resp); + return tl::make_unexpected(resp.error()); } -PutObjectResponse BaseClient::PutObject(PutObjectApiArgs args) { +Result BaseClient::PutObject(PutObjectApiArgs args) { if (error::Error err = args.Validate()) { - return PutObjectResponse(err); + return tl::make_unexpected(err); } std::string region; - if (GetRegionResponse resp = GetRegion(args.bucket, args.region)) { - region = resp.region; + auto get_resp = GetRegion(args.bucket, args.region); + if (get_resp) { + region = get_resp->region; } else { - return PutObjectResponse(resp); + return tl::make_unexpected(get_resp.error()); } #ifdef MINIO_CPP_RDMA @@ -1426,51 +1479,57 @@ PutObjectResponse BaseClient::PutObject(PutObjectApiArgs args) { req.progressfunc = args.progressfunc; req.progress_userdata = args.progress_userdata; - Response response = Execute(req); + auto response = Execute(req); if (!response) { - return PutObjectResponse(response); + return tl::make_unexpected(response.error()); } PutObjectResponse resp; - resp.etag = utils::Trim(response.headers.GetFront("etag"), '"'); - resp.version_id = response.headers.GetFront("x-amz-version-id"); - resp.checksumCRC32 = response.headers.GetFront("x-amz-checksum-crc32"); - resp.checksumCRC32C = response.headers.GetFront("x-amz-checksum-crc32c"); - resp.checksumSHA1 = response.headers.GetFront("x-amz-checksum-sha1"); - resp.checksumSHA256 = response.headers.GetFront("x-amz-checksum-sha256"); + resp.etag = utils::Trim(response->headers.GetFront("etag"), '"'); + resp.version_id = response->headers.GetFront("x-amz-version-id"); + resp.checksumCRC32 = response->headers.GetFront("x-amz-checksum-crc32"); + resp.checksumCRC32C = response->headers.GetFront("x-amz-checksum-crc32c"); + resp.checksumSHA1 = response->headers.GetFront("x-amz-checksum-sha1"); + resp.checksumSHA256 = response->headers.GetFront("x-amz-checksum-sha256"); return resp; } -RemoveBucketResponse BaseClient::RemoveBucket(RemoveBucketArgs args) { +Result BaseClient::RemoveBucket(RemoveBucketArgs args) { if (error::Error err = args.Validate()) { - return RemoveBucketResponse(err); + return tl::make_unexpected(err); } std::string region; - if (GetRegionResponse resp = GetRegion(args.bucket, args.region)) { - region = resp.region; + auto get_resp = GetRegion(args.bucket, args.region); + if (get_resp) { + region = get_resp->region; } else { - return RemoveBucketResponse(resp); + return tl::make_unexpected(get_resp.error()); } Request req(http::Method::kDelete, region, base_url_, args.extra_headers, args.extra_query_params); req.bucket_name = args.bucket; - return RemoveBucketResponse(Execute(req)); + auto exec_set = Execute(req); + + if (!exec_set) return tl::make_unexpected(exec_set.error()); + + return RemoveBucketResponse(std::move(*exec_set)); } -RemoveObjectResponse BaseClient::RemoveObject(RemoveObjectArgs args) { +Result BaseClient::RemoveObject(RemoveObjectArgs args) { if (error::Error err = args.Validate()) { - return RemoveObjectResponse(err); + return tl::make_unexpected(err); } std::string region; - if (GetRegionResponse resp = GetRegion(args.bucket, args.region)) { - region = resp.region; + auto get_resp = GetRegion(args.bucket, args.region); + if (get_resp) { + region = get_resp->region; } else { - return RemoveObjectResponse(resp); + return tl::make_unexpected(get_resp.error()); } Request req(http::Method::kDelete, region, base_url_, args.extra_headers, @@ -1481,19 +1540,25 @@ RemoveObjectResponse BaseClient::RemoveObject(RemoveObjectArgs args) { req.query_params.Add("versionId", args.version_id); } - return RemoveObjectResponse(Execute(req)); + auto exec_set = Execute(req); + + if (!exec_set) return tl::make_unexpected(exec_set.error()); + + return RemoveObjectResponse(std::move(*exec_set)); } -RemoveObjectsResponse BaseClient::RemoveObjects(RemoveObjectsApiArgs args) { +Result BaseClient::RemoveObjects( + RemoveObjectsApiArgs args) { if (error::Error err = args.Validate()) { - return RemoveObjectsResponse(err); + return tl::make_unexpected(err); } std::string region; - if (GetRegionResponse resp = GetRegion(args.bucket, args.region)) { - region = resp.region; + auto get_resp = GetRegion(args.bucket, args.region); + if (get_resp) { + region = get_resp->region; } else { - return RemoveObjectsResponse(resp); + return tl::make_unexpected(get_resp.error()); } Request req(http::Method::kPost, region, base_url_, args.extra_headers, @@ -1521,17 +1586,17 @@ RemoveObjectsResponse BaseClient::RemoveObjects(RemoveObjectsApiArgs args) { req.headers.Add("Content-Type", "application/xml"); req.headers.Add("Content-MD5", utils::Md5sumHash(body)); - Response response = Execute(req); + auto response = Execute(req); if (!response) { - return RemoveObjectsResponse(response); + return tl::make_unexpected(response.error()); } - return RemoveObjectsResponse::ParseXML(response.data); + return RemoveObjectsResponse::ParseXML(response->data); } -SelectObjectContentResponse BaseClient::SelectObjectContent( +Result BaseClient::SelectObjectContent( SelectObjectContentArgs args) { if (error::Error err = args.Validate()) { - return SelectObjectContentResponse(err); + return tl::make_unexpected(err); } if (args.ssec != nullptr && !base_url_.https) { @@ -1540,10 +1605,11 @@ SelectObjectContentResponse BaseClient::SelectObjectContent( } std::string region; - if (GetRegionResponse resp = GetRegion(args.bucket, args.region)) { - region = resp.region; + auto get_resp = GetRegion(args.bucket, args.region); + if (get_resp) { + region = get_resp->region; } else { - return SelectObjectContentResponse(resp); + return tl::make_unexpected(get_resp.error()); } Request req(http::Method::kPost, region, base_url_, args.extra_headers, @@ -1560,20 +1626,25 @@ SelectObjectContentResponse BaseClient::SelectObjectContent( using namespace std::placeholders; req.datafunc = std::bind(&SelectHandler::DataFunction, &handler, _1); - return SelectObjectContentResponse(Execute(req)); + auto exec_set = Execute(req); + + if (!exec_set) return tl::make_unexpected(exec_set.error()); + + return SelectObjectContentResponse(std::move(*exec_set)); } -SetBucketEncryptionResponse BaseClient::SetBucketEncryption( +Result BaseClient::SetBucketEncryption( SetBucketEncryptionArgs args) { if (error::Error err = args.Validate()) { - return SetBucketEncryptionResponse(err); + return tl::make_unexpected(err); } std::string region; - if (GetRegionResponse resp = GetRegion(args.bucket, args.region)) { - region = resp.region; + auto get_resp = GetRegion(args.bucket, args.region); + if (get_resp) { + region = get_resp->region; } else { - return SetBucketEncryptionResponse(resp); + return tl::make_unexpected(get_resp.error()); } std::stringstream ss; @@ -1595,20 +1666,25 @@ SetBucketEncryptionResponse BaseClient::SetBucketEncryption( req.headers.Add("Content-MD5", utils::Md5sumHash(body)); req.body = std::move(body); - return SetBucketEncryptionResponse(Execute(req)); + auto exec_set = Execute(req); + + if (!exec_set) return tl::make_unexpected(exec_set.error()); + + return SetBucketEncryptionResponse(std::move(*exec_set)); } -SetBucketLifecycleResponse BaseClient::SetBucketLifecycle( +Result BaseClient::SetBucketLifecycle( SetBucketLifecycleArgs args) { if (error::Error err = args.Validate()) { - return SetBucketLifecycleResponse(err); + return tl::make_unexpected(err); } std::string region; - if (GetRegionResponse resp = GetRegion(args.bucket, args.region)) { - region = resp.region; + auto get_resp = GetRegion(args.bucket, args.region); + if (get_resp) { + region = get_resp->region; } else { - return SetBucketLifecycleResponse(resp); + return tl::make_unexpected(get_resp.error()); } std::string body = args.config.ToXML(); @@ -1620,20 +1696,25 @@ SetBucketLifecycleResponse BaseClient::SetBucketLifecycle( req.headers.Add("Content-MD5", utils::Md5sumHash(body)); req.body = std::move(body); - return SetBucketLifecycleResponse(Execute(req)); + auto exec_set = Execute(req); + + if (!exec_set) return tl::make_unexpected(exec_set.error()); + + return SetBucketLifecycleResponse(std::move(*exec_set)); } -SetBucketNotificationResponse BaseClient::SetBucketNotification( +Result BaseClient::SetBucketNotification( SetBucketNotificationArgs args) { if (error::Error err = args.Validate()) { - return SetBucketNotificationResponse(err); + return tl::make_unexpected(err); } std::string region; - if (GetRegionResponse resp = GetRegion(args.bucket, args.region)) { - region = resp.region; + auto get_resp = GetRegion(args.bucket, args.region); + if (get_resp) { + region = get_resp->region; } else { - return SetBucketNotificationResponse(resp); + return tl::make_unexpected(get_resp.error()); } std::string body = args.config.ToXML(); @@ -1645,19 +1726,25 @@ SetBucketNotificationResponse BaseClient::SetBucketNotification( req.headers.Add("Content-MD5", utils::Md5sumHash(body)); req.body = std::move(body); - return SetBucketNotificationResponse(Execute(req)); + auto exec_set = Execute(req); + + if (!exec_set) return tl::make_unexpected(exec_set.error()); + + return SetBucketNotificationResponse(std::move(*exec_set)); } -SetBucketPolicyResponse BaseClient::SetBucketPolicy(SetBucketPolicyArgs args) { +Result BaseClient::SetBucketPolicy( + SetBucketPolicyArgs args) { if (error::Error err = args.Validate()) { - return SetBucketPolicyResponse(err); + return tl::make_unexpected(err); } std::string region; - if (GetRegionResponse resp = GetRegion(args.bucket, args.region)) { - region = resp.region; + auto get_resp = GetRegion(args.bucket, args.region); + if (get_resp) { + region = get_resp->region; } else { - return SetBucketPolicyResponse(resp); + return tl::make_unexpected(get_resp.error()); } Request req(http::Method::kPut, region, base_url_, args.extra_headers, @@ -1667,20 +1754,25 @@ SetBucketPolicyResponse BaseClient::SetBucketPolicy(SetBucketPolicyArgs args) { req.body = args.policy; req.headers.Add("Content-MD5", utils::Md5sumHash(args.policy)); - return SetBucketPolicyResponse(Execute(req)); + auto exec_set = Execute(req); + + if (!exec_set) return tl::make_unexpected(exec_set.error()); + + return SetBucketPolicyResponse(std::move(*exec_set)); } -SetBucketReplicationResponse BaseClient::SetBucketReplication( +Result BaseClient::SetBucketReplication( SetBucketReplicationArgs args) { if (error::Error err = args.Validate()) { - return SetBucketReplicationResponse(err); + return tl::make_unexpected(err); } std::string region; - if (GetRegionResponse resp = GetRegion(args.bucket, args.region)) { - region = resp.region; + auto get_resp = GetRegion(args.bucket, args.region); + if (get_resp) { + region = get_resp->region; } else { - return SetBucketReplicationResponse(resp); + return tl::make_unexpected(get_resp.error()); } std::string body = args.config.ToXML(); @@ -1692,19 +1784,25 @@ SetBucketReplicationResponse BaseClient::SetBucketReplication( req.headers.Add("Content-MD5", utils::Md5sumHash(body)); req.body = std::move(body); - return SetBucketReplicationResponse(Execute(req)); + auto exec_set = Execute(req); + + if (!exec_set) return tl::make_unexpected(exec_set.error()); + + return SetBucketReplicationResponse(std::move(*exec_set)); } -SetBucketTagsResponse BaseClient::SetBucketTags(SetBucketTagsArgs args) { +Result BaseClient::SetBucketTags( + SetBucketTagsArgs args) { if (error::Error err = args.Validate()) { - return SetBucketTagsResponse(err); + return tl::make_unexpected(err); } std::string region; - if (GetRegionResponse resp = GetRegion(args.bucket, args.region)) { - region = resp.region; + auto get_resp = GetRegion(args.bucket, args.region); + if (get_resp) { + region = get_resp->region; } else { - return SetBucketTagsResponse(resp); + return tl::make_unexpected(get_resp.error()); } std::stringstream ss; @@ -1728,20 +1826,25 @@ SetBucketTagsResponse BaseClient::SetBucketTags(SetBucketTagsArgs args) { req.headers.Add("Content-MD5", utils::Md5sumHash(body)); req.body = std::move(body); - return SetBucketTagsResponse(Execute(req)); + auto exec_set = Execute(req); + + if (!exec_set) return tl::make_unexpected(exec_set.error()); + + return SetBucketTagsResponse(std::move(*exec_set)); } -SetBucketVersioningResponse BaseClient::SetBucketVersioning( +Result BaseClient::SetBucketVersioning( SetBucketVersioningArgs args) { if (error::Error err = args.Validate()) { - return SetBucketVersioningResponse(err); + return tl::make_unexpected(err); } std::string region; - if (GetRegionResponse resp = GetRegion(args.bucket, args.region)) { - region = resp.region; + auto get_resp = GetRegion(args.bucket, args.region); + if (get_resp) { + region = get_resp->region; } else { - return SetBucketVersioningResponse(resp); + return tl::make_unexpected(get_resp.error()); } std::stringstream ss; @@ -1764,20 +1867,25 @@ SetBucketVersioningResponse BaseClient::SetBucketVersioning( req.headers.Add("Content-MD5", utils::Md5sumHash(body)); req.body = std::move(body); - return SetBucketVersioningResponse(Execute(req)); + auto exec_set = Execute(req); + + if (!exec_set) return tl::make_unexpected(exec_set.error()); + + return SetBucketVersioningResponse(std::move(*exec_set)); } -SetObjectLockConfigResponse BaseClient::SetObjectLockConfig( +Result BaseClient::SetObjectLockConfig( SetObjectLockConfigArgs args) { if (error::Error err = args.Validate()) { - return SetObjectLockConfigResponse(err); + return tl::make_unexpected(err); } std::string region; - if (GetRegionResponse resp = GetRegion(args.bucket, args.region)) { - region = resp.region; + auto get_resp = GetRegion(args.bucket, args.region); + if (get_resp) { + region = get_resp->region; } else { - return SetObjectLockConfigResponse(resp); + return tl::make_unexpected(get_resp.error()); } std::stringstream ss; @@ -1810,20 +1918,25 @@ SetObjectLockConfigResponse BaseClient::SetObjectLockConfig( req.headers.Add("Content-MD5", utils::Md5sumHash(body)); req.body = std::move(body); - return SetObjectLockConfigResponse(Execute(req)); + auto exec_set = Execute(req); + + if (!exec_set) return tl::make_unexpected(exec_set.error()); + + return SetObjectLockConfigResponse(std::move(*exec_set)); } -SetObjectRetentionResponse BaseClient::SetObjectRetention( +Result BaseClient::SetObjectRetention( SetObjectRetentionArgs args) { if (error::Error err = args.Validate()) { - return SetObjectRetentionResponse(err); + return tl::make_unexpected(err); } std::string region; - if (GetRegionResponse resp = GetRegion(args.bucket, args.region)) { - region = resp.region; + auto get_resp = GetRegion(args.bucket, args.region); + if (get_resp) { + region = get_resp->region; } else { - return SetObjectRetentionResponse(resp); + return tl::make_unexpected(get_resp.error()); } std::stringstream ss; @@ -1845,19 +1958,25 @@ SetObjectRetentionResponse BaseClient::SetObjectRetention( req.headers.Add("Content-MD5", utils::Md5sumHash(body)); req.body = std::move(body); - return SetObjectRetentionResponse(Execute(req)); + auto exec_set = Execute(req); + + if (!exec_set) return tl::make_unexpected(exec_set.error()); + + return SetObjectRetentionResponse(std::move(*exec_set)); } -SetObjectTagsResponse BaseClient::SetObjectTags(SetObjectTagsArgs args) { +Result BaseClient::SetObjectTags( + SetObjectTagsArgs args) { if (error::Error err = args.Validate()) { - return SetObjectTagsResponse(err); + return tl::make_unexpected(err); } std::string region; - if (GetRegionResponse resp = GetRegion(args.bucket, args.region)) { - region = resp.region; + auto get_resp = GetRegion(args.bucket, args.region); + if (get_resp) { + region = get_resp->region; } else { - return SetObjectTagsResponse(resp); + return tl::make_unexpected(get_resp.error()); } std::stringstream ss; @@ -1885,12 +2004,16 @@ SetObjectTagsResponse BaseClient::SetObjectTags(SetObjectTagsArgs args) { req.headers.Add("Content-MD5", utils::Md5sumHash(body)); req.body = std::move(body); - return SetObjectTagsResponse(Execute(req)); + auto exec_set = Execute(req); + + if (!exec_set) return tl::make_unexpected(exec_set.error()); + + return SetObjectTagsResponse(std::move(*exec_set)); } -StatObjectResponse BaseClient::StatObject(StatObjectArgs args) { +Result BaseClient::StatObject(StatObjectArgs args) { if (error::Error err = args.Validate()) { - return StatObjectResponse(err); + return tl::make_unexpected(err); } if (args.ssec != nullptr && !base_url_.https) { @@ -1899,10 +2022,11 @@ StatObjectResponse BaseClient::StatObject(StatObjectArgs args) { } std::string region; - if (GetRegionResponse resp = GetRegion(args.bucket, args.region)) { - region = resp.region; + auto get_resp = GetRegion(args.bucket, args.region); + if (get_resp) { + region = get_resp->region; } else { - return StatObjectResponse(resp); + return tl::make_unexpected(get_resp.error()); } Request req(http::Method::kHead, region, base_url_, args.extra_headers, @@ -1914,45 +2038,45 @@ StatObjectResponse BaseClient::StatObject(StatObjectArgs args) { } req.headers.AddAll(args.Headers()); - Response response = Execute(req); + auto response = Execute(req); if (!response) { - return StatObjectResponse(response); + return tl::make_unexpected(response.error()); } - StatObjectResponse resp(response); + StatObjectResponse resp(std::move(*response)); resp.bucket_name = args.bucket; resp.object_name = args.object; - resp.version_id = response.headers.GetFront("x-amz-version-id"); + resp.version_id = response->headers.GetFront("x-amz-version-id"); - resp.etag = utils::Trim(response.headers.GetFront("etag"), '"'); + resp.etag = utils::Trim(response->headers.GetFront("etag"), '"'); - std::string value = response.headers.GetFront("content-length"); + std::string value = response->headers.GetFront("content-length"); if (!value.empty()) resp.size = std::stol(value); - value = response.headers.GetFront("last-modified"); + value = response->headers.GetFront("last-modified"); if (!value.empty()) { resp.last_modified = utils::UtcTime::FromHttpHeaderValue(value.c_str()); } - value = response.headers.GetFront("x-amz-object-lock-mode"); + value = response->headers.GetFront("x-amz-object-lock-mode"); if (!value.empty()) resp.retention_mode = StringToRetentionMode(value); - value = response.headers.GetFront("x-amz-object-lock-retain-until-date"); + value = response->headers.GetFront("x-amz-object-lock-retain-until-date"); if (!value.empty()) { resp.retention_retain_until_date = utils::UtcTime::FromISO8601UTC(value.c_str()); } - value = response.headers.GetFront("x-amz-object-lock-legal-hold"); + value = response->headers.GetFront("x-amz-object-lock-legal-hold"); if (!value.empty()) resp.legal_hold = StringToLegalHold(value); - value = response.headers.GetFront("x-amz-delete-marker"); + value = response->headers.GetFront("x-amz-delete-marker"); if (!value.empty()) resp.delete_marker = utils::StringToBool(value); utils::Multimap user_metadata; - std::list keys = response.headers.Keys(); + std::list keys = response->headers.Keys(); for (auto key : keys) { if (utils::StartsWith(key, "x-amz-meta-")) { - std::list values = response.headers.Get(key); + std::list values = response->headers.Get(key); key.erase(0, 11); for (auto value : values) user_metadata.Add(key, value); } @@ -1962,18 +2086,19 @@ StatObjectResponse BaseClient::StatObject(StatObjectArgs args) { return resp; } -UploadPartResponse BaseClient::UploadPart(UploadPartArgs args) { +Result BaseClient::UploadPart(UploadPartArgs args) { if (error::Error err = args.Validate()) { - return UploadPartResponse(err); + return tl::make_unexpected(err); } #ifdef MINIO_CPP_RDMA if (args.rdmaclient != nullptr && args.rdmaclient->isConnected()) { std::string region; - if (GetRegionResponse resp = GetRegion(args.bucket, args.region)) { - region = resp.region; + auto get_resp = GetRegion(args.bucket, args.region); + if (get_resp) { + region = get_resp->region; } else { - return UploadPartResponse(resp); + return tl::make_unexpected(get_resp.error()); } s3_rdma_client_ctx putCtx = { @@ -2017,19 +2142,23 @@ UploadPartResponse BaseClient::UploadPart(UploadPartArgs args) { api_args.progress_userdata = args.progress_userdata; api_args.query_params = query_params; - return UploadPartResponse(PutObject(api_args)); + auto put_obj = PutObject(api_args); + if (!put_obj) return tl::make_unexpected(put_obj.error()); + return UploadPartResponse(std::move(*put_obj)); } -UploadPartCopyResponse BaseClient::UploadPartCopy(UploadPartCopyArgs args) { +Result BaseClient::UploadPartCopy( + UploadPartCopyArgs args) { if (error::Error err = args.Validate()) { - return UploadPartCopyResponse(err); + return tl::make_unexpected(err); } std::string region; - if (GetRegionResponse resp = GetRegion(args.bucket, args.region)) { - region = resp.region; + auto get_resp = GetRegion(args.bucket, args.region); + if (get_resp) { + region = get_resp->region; } else { - return UploadPartCopyResponse(resp); + return tl::make_unexpected(get_resp.error()); } Request req(http::Method::kPut, region, base_url_, args.extra_headers, @@ -2041,27 +2170,27 @@ UploadPartCopyResponse BaseClient::UploadPartCopy(UploadPartCopyArgs args) { req.query_params.Add("uploadId", args.upload_id); req.headers.AddAll(args.headers); - Response response = Execute(req); + auto response = Execute(req); if (!response) { - return UploadPartCopyResponse(response); + return tl::make_unexpected(response.error()); } UploadPartCopyResponse resp; - resp.etag = utils::Trim(response.headers.GetFront("etag"), '"'); + resp.etag = utils::Trim(response->headers.GetFront("etag"), '"'); return resp; } // ---- Async overloads ---- -std::future BaseClient::AbortMultipartUploadAsync( - AbortMultipartUploadArgs args) { +std::future> +BaseClient::AbortMultipartUploadAsync(AbortMultipartUploadArgs args) { return std::async(std::launch::async, [this, args = std::move(args)]() mutable { return AbortMultipartUpload(std::move(args)); }); } -std::future BaseClient::BucketExistsAsync( +std::future> BaseClient::BucketExistsAsync( BucketExistsArgs args) { return std::async(std::launch::async, [this, args = std::move(args)]() mutable { @@ -2069,7 +2198,7 @@ std::future BaseClient::BucketExistsAsync( }); } -std::future +std::future> BaseClient::CompleteMultipartUploadAsync(CompleteMultipartUploadArgs args) { return std::async(std::launch::async, [this, args = std::move(args)]() mutable { @@ -2077,7 +2206,7 @@ BaseClient::CompleteMultipartUploadAsync(CompleteMultipartUploadArgs args) { }); } -std::future +std::future> BaseClient::CreateMultipartUploadAsync(CreateMultipartUploadArgs args) { return std::async(std::launch::async, [this, args = std::move(args)]() mutable { @@ -2085,7 +2214,7 @@ BaseClient::CreateMultipartUploadAsync(CreateMultipartUploadArgs args) { }); } -std::future +std::future> BaseClient::DeleteBucketEncryptionAsync(DeleteBucketEncryptionArgs args) { return std::async(std::launch::async, [this, args = std::move(args)]() mutable { @@ -2093,7 +2222,7 @@ BaseClient::DeleteBucketEncryptionAsync(DeleteBucketEncryptionArgs args) { }); } -std::future +std::future> BaseClient::DeleteBucketLifecycleAsync(DeleteBucketLifecycleArgs args) { return std::async(std::launch::async, [this, args = std::move(args)]() mutable { @@ -2101,7 +2230,7 @@ BaseClient::DeleteBucketLifecycleAsync(DeleteBucketLifecycleArgs args) { }); } -std::future +std::future> BaseClient::DeleteBucketNotificationAsync(DeleteBucketNotificationArgs args) { return std::async(std::launch::async, [this, args = std::move(args)]() mutable { @@ -2109,15 +2238,15 @@ BaseClient::DeleteBucketNotificationAsync(DeleteBucketNotificationArgs args) { }); } -std::future BaseClient::DeleteBucketPolicyAsync( - DeleteBucketPolicyArgs args) { +std::future> +BaseClient::DeleteBucketPolicyAsync(DeleteBucketPolicyArgs args) { return std::async(std::launch::async, [this, args = std::move(args)]() mutable { return DeleteBucketPolicy(std::move(args)); }); } -std::future +std::future> BaseClient::DeleteBucketReplicationAsync(DeleteBucketReplicationArgs args) { return std::async(std::launch::async, [this, args = std::move(args)]() mutable { @@ -2125,7 +2254,7 @@ BaseClient::DeleteBucketReplicationAsync(DeleteBucketReplicationArgs args) { }); } -std::future BaseClient::DeleteBucketTagsAsync( +std::future> BaseClient::DeleteBucketTagsAsync( DeleteBucketTagsArgs args) { return std::async(std::launch::async, [this, args = std::move(args)]() mutable { @@ -2133,7 +2262,7 @@ std::future BaseClient::DeleteBucketTagsAsync( }); } -std::future +std::future> BaseClient::DeleteObjectLockConfigAsync(DeleteObjectLockConfigArgs args) { return std::async(std::launch::async, [this, args = std::move(args)]() mutable { @@ -2141,7 +2270,7 @@ BaseClient::DeleteObjectLockConfigAsync(DeleteObjectLockConfigArgs args) { }); } -std::future BaseClient::DeleteObjectTagsAsync( +std::future> BaseClient::DeleteObjectTagsAsync( DeleteObjectTagsArgs args) { return std::async(std::launch::async, [this, args = std::move(args)]() mutable { @@ -2149,7 +2278,7 @@ std::future BaseClient::DeleteObjectTagsAsync( }); } -std::future +std::future> BaseClient::DisableObjectLegalHoldAsync(DisableObjectLegalHoldArgs args) { return std::async(std::launch::async, [this, args = std::move(args)]() mutable { @@ -2157,7 +2286,7 @@ BaseClient::DisableObjectLegalHoldAsync(DisableObjectLegalHoldArgs args) { }); } -std::future +std::future> BaseClient::EnableObjectLegalHoldAsync(EnableObjectLegalHoldArgs args) { return std::async(std::launch::async, [this, args = std::move(args)]() mutable { @@ -2165,23 +2294,23 @@ BaseClient::EnableObjectLegalHoldAsync(EnableObjectLegalHoldArgs args) { }); } -std::future BaseClient::GetBucketEncryptionAsync( - GetBucketEncryptionArgs args) { +std::future> +BaseClient::GetBucketEncryptionAsync(GetBucketEncryptionArgs args) { return std::async(std::launch::async, [this, args = std::move(args)]() mutable { return GetBucketEncryption(std::move(args)); }); } -std::future BaseClient::GetBucketLifecycleAsync( - GetBucketLifecycleArgs args) { +std::future> +BaseClient::GetBucketLifecycleAsync(GetBucketLifecycleArgs args) { return std::async(std::launch::async, [this, args = std::move(args)]() mutable { return GetBucketLifecycle(std::move(args)); }); } -std::future +std::future> BaseClient::GetBucketNotificationAsync(GetBucketNotificationArgs args) { return std::async(std::launch::async, [this, args = std::move(args)]() mutable { @@ -2189,7 +2318,7 @@ BaseClient::GetBucketNotificationAsync(GetBucketNotificationArgs args) { }); } -std::future BaseClient::GetBucketPolicyAsync( +std::future> BaseClient::GetBucketPolicyAsync( GetBucketPolicyArgs args) { return std::async(std::launch::async, [this, args = std::move(args)]() mutable { @@ -2197,15 +2326,15 @@ std::future BaseClient::GetBucketPolicyAsync( }); } -std::future BaseClient::GetBucketReplicationAsync( - GetBucketReplicationArgs args) { +std::future> +BaseClient::GetBucketReplicationAsync(GetBucketReplicationArgs args) { return std::async(std::launch::async, [this, args = std::move(args)]() mutable { return GetBucketReplication(std::move(args)); }); } -std::future BaseClient::GetBucketTagsAsync( +std::future> BaseClient::GetBucketTagsAsync( GetBucketTagsArgs args) { return std::async(std::launch::async, [this, args = std::move(args)]() mutable { @@ -2213,38 +2342,39 @@ std::future BaseClient::GetBucketTagsAsync( }); } -std::future BaseClient::GetBucketVersioningAsync( - GetBucketVersioningArgs args) { +std::future> +BaseClient::GetBucketVersioningAsync(GetBucketVersioningArgs args) { return std::async(std::launch::async, [this, args = std::move(args)]() mutable { return GetBucketVersioning(std::move(args)); }); } -std::future BaseClient::GetObjectAsync(GetObjectArgs args) { +std::future> BaseClient::GetObjectAsync( + GetObjectArgs args) { return std::async(std::launch::async, [this, args = std::move(args)]() mutable { return GetObject(std::move(args)); }); } -std::future BaseClient::GetObjectLockConfigAsync( - GetObjectLockConfigArgs args) { +std::future> +BaseClient::GetObjectLockConfigAsync(GetObjectLockConfigArgs args) { return std::async(std::launch::async, [this, args = std::move(args)]() mutable { return GetObjectLockConfig(std::move(args)); }); } -std::future BaseClient::GetObjectRetentionAsync( - GetObjectRetentionArgs args) { +std::future> +BaseClient::GetObjectRetentionAsync(GetObjectRetentionArgs args) { return std::async(std::launch::async, [this, args = std::move(args)]() mutable { return GetObjectRetention(std::move(args)); }); } -std::future BaseClient::GetObjectTagsAsync( +std::future> BaseClient::GetObjectTagsAsync( GetObjectTagsArgs args) { return std::async(std::launch::async, [this, args = std::move(args)]() mutable { @@ -2252,7 +2382,7 @@ std::future BaseClient::GetObjectTagsAsync( }); } -std::future +std::future> BaseClient::GetPresignedObjectUrlAsync(GetPresignedObjectUrlArgs args) { return std::async(std::launch::async, [this, args = std::move(args)]() mutable { @@ -2260,7 +2390,7 @@ BaseClient::GetPresignedObjectUrlAsync(GetPresignedObjectUrlArgs args) { }); } -std::future +std::future> BaseClient::GetPresignedPostFormDataAsync(PostPolicy policy) { return std::async(std::launch::async, [this, policy = std::move(policy)]() mutable { @@ -2268,7 +2398,7 @@ BaseClient::GetPresignedPostFormDataAsync(PostPolicy policy) { }); } -std::future +std::future> BaseClient::IsObjectLegalHoldEnabledAsync(IsObjectLegalHoldEnabledArgs args) { return std::async(std::launch::async, [this, args = std::move(args)]() mutable { @@ -2276,7 +2406,7 @@ BaseClient::IsObjectLegalHoldEnabledAsync(IsObjectLegalHoldEnabledArgs args) { }); } -std::future BaseClient::ListBucketsAsync( +std::future> BaseClient::ListBucketsAsync( ListBucketsArgs args) { return std::async(std::launch::async, [this, args = std::move(args)]() mutable { @@ -2284,11 +2414,11 @@ std::future BaseClient::ListBucketsAsync( }); } -std::future BaseClient::ListBucketsAsync() { +std::future> BaseClient::ListBucketsAsync() { return std::async(std::launch::async, [this]() { return ListBuckets(); }); } -std::future +std::future> BaseClient::ListenBucketNotificationAsync(ListenBucketNotificationArgs args) { return std::async(std::launch::async, [this, args = std::move(args)]() mutable { @@ -2296,7 +2426,7 @@ BaseClient::ListenBucketNotificationAsync(ListenBucketNotificationArgs args) { }); } -std::future BaseClient::ListObjectsV1Async( +std::future> BaseClient::ListObjectsV1Async( ListObjectsV1Args args) { return std::async(std::launch::async, [this, args = std::move(args)]() mutable { @@ -2304,7 +2434,7 @@ std::future BaseClient::ListObjectsV1Async( }); } -std::future BaseClient::ListObjectsV2Async( +std::future> BaseClient::ListObjectsV2Async( ListObjectsV2Args args) { return std::async(std::launch::async, [this, args = std::move(args)]() mutable { @@ -2312,7 +2442,7 @@ std::future BaseClient::ListObjectsV2Async( }); } -std::future BaseClient::ListObjectVersionsAsync( +std::future> BaseClient::ListObjectVersionsAsync( ListObjectVersionsArgs args) { return std::async(std::launch::async, [this, args = std::move(args)]() mutable { @@ -2320,7 +2450,7 @@ std::future BaseClient::ListObjectVersionsAsync( }); } -std::future BaseClient::MakeBucketAsync( +std::future> BaseClient::MakeBucketAsync( MakeBucketArgs args) { return std::async(std::launch::async, [this, args = std::move(args)]() mutable { @@ -2328,7 +2458,7 @@ std::future BaseClient::MakeBucketAsync( }); } -std::future BaseClient::PutObjectAsync( +std::future> BaseClient::PutObjectAsync( PutObjectApiArgs args) { return std::async(std::launch::async, [this, args = std::move(args)]() mutable { @@ -2336,7 +2466,7 @@ std::future BaseClient::PutObjectAsync( }); } -std::future BaseClient::RemoveBucketAsync( +std::future> BaseClient::RemoveBucketAsync( RemoveBucketArgs args) { return std::async(std::launch::async, [this, args = std::move(args)]() mutable { @@ -2344,7 +2474,7 @@ std::future BaseClient::RemoveBucketAsync( }); } -std::future BaseClient::RemoveObjectAsync( +std::future> BaseClient::RemoveObjectAsync( RemoveObjectArgs args) { return std::async(std::launch::async, [this, args = std::move(args)]() mutable { @@ -2352,7 +2482,7 @@ std::future BaseClient::RemoveObjectAsync( }); } -std::future BaseClient::RemoveObjectsAsync( +std::future> BaseClient::RemoveObjectsAsync( RemoveObjectsApiArgs args) { return std::async(std::launch::async, [this, args = std::move(args)]() mutable { @@ -2362,8 +2492,8 @@ std::future BaseClient::RemoveObjectsAsync( // SelectObjectContentArgs owns request by value (deep-copied via // SelectRequest's shared_ptr chain). Direct move is safe. -std::future BaseClient::SelectObjectContentAsync( - SelectObjectContentArgs args) { +std::future> +BaseClient::SelectObjectContentAsync(SelectObjectContentArgs args) { return std::async(std::launch::async, [this, args = std::move(args)]() mutable { return SelectObjectContent(std::move(args)); @@ -2371,8 +2501,8 @@ std::future BaseClient::SelectObjectContentAsync( } // SetBucketEncryptionArgs owns config by value. -std::future BaseClient::SetBucketEncryptionAsync( - SetBucketEncryptionArgs args) { +std::future> +BaseClient::SetBucketEncryptionAsync(SetBucketEncryptionArgs args) { return std::async(std::launch::async, [this, args = std::move(args)]() mutable { return SetBucketEncryption(std::move(args)); @@ -2380,8 +2510,8 @@ std::future BaseClient::SetBucketEncryptionAsync( } // SetBucketLifecycleArgs owns config by value. -std::future BaseClient::SetBucketLifecycleAsync( - SetBucketLifecycleArgs args) { +std::future> +BaseClient::SetBucketLifecycleAsync(SetBucketLifecycleArgs args) { return std::async(std::launch::async, [this, args = std::move(args)]() mutable { return SetBucketLifecycle(std::move(args)); @@ -2390,7 +2520,7 @@ std::future BaseClient::SetBucketLifecycleAsync( // SetBucketNotificationArgs owns config by value. // config. -std::future +std::future> BaseClient::SetBucketNotificationAsync(SetBucketNotificationArgs args) { return std::async(std::launch::async, [this, args = std::move(args)]() mutable { @@ -2399,15 +2529,15 @@ BaseClient::SetBucketNotificationAsync(SetBucketNotificationArgs args) { } // SetBucketReplicationArgs owns config by value. -std::future BaseClient::SetBucketReplicationAsync( - SetBucketReplicationArgs args) { +std::future> +BaseClient::SetBucketReplicationAsync(SetBucketReplicationArgs args) { return std::async(std::launch::async, [this, args = std::move(args)]() mutable { return SetBucketReplication(std::move(args)); }); } -std::future BaseClient::SetBucketPolicyAsync( +std::future> BaseClient::SetBucketPolicyAsync( SetBucketPolicyArgs args) { return std::async(std::launch::async, [this, args = std::move(args)]() mutable { @@ -2415,7 +2545,7 @@ std::future BaseClient::SetBucketPolicyAsync( }); } -std::future BaseClient::SetBucketTagsAsync( +std::future> BaseClient::SetBucketTagsAsync( SetBucketTagsArgs args) { return std::async(std::launch::async, [this, args = std::move(args)]() mutable { @@ -2423,31 +2553,31 @@ std::future BaseClient::SetBucketTagsAsync( }); } -std::future BaseClient::SetBucketVersioningAsync( - SetBucketVersioningArgs args) { +std::future> +BaseClient::SetBucketVersioningAsync(SetBucketVersioningArgs args) { return std::async(std::launch::async, [this, args = std::move(args)]() mutable { return SetBucketVersioning(std::move(args)); }); } -std::future BaseClient::SetObjectLockConfigAsync( - SetObjectLockConfigArgs args) { +std::future> +BaseClient::SetObjectLockConfigAsync(SetObjectLockConfigArgs args) { return std::async(std::launch::async, [this, args = std::move(args)]() mutable { return SetObjectLockConfig(std::move(args)); }); } -std::future BaseClient::SetObjectRetentionAsync( - SetObjectRetentionArgs args) { +std::future> +BaseClient::SetObjectRetentionAsync(SetObjectRetentionArgs args) { return std::async(std::launch::async, [this, args = std::move(args)]() mutable { return SetObjectRetention(std::move(args)); }); } -std::future BaseClient::SetObjectTagsAsync( +std::future> BaseClient::SetObjectTagsAsync( SetObjectTagsArgs args) { return std::async(std::launch::async, [this, args = std::move(args)]() mutable { @@ -2455,7 +2585,7 @@ std::future BaseClient::SetObjectTagsAsync( }); } -std::future BaseClient::StatObjectAsync( +std::future> BaseClient::StatObjectAsync( StatObjectArgs args) { return std::async(std::launch::async, [this, args = std::move(args)]() mutable { @@ -2463,7 +2593,7 @@ std::future BaseClient::StatObjectAsync( }); } -std::future BaseClient::UploadPartAsync( +std::future> BaseClient::UploadPartAsync( UploadPartArgs args) { return std::async(std::launch::async, [this, args = std::move(args)]() mutable { @@ -2471,7 +2601,7 @@ std::future BaseClient::UploadPartAsync( }); } -std::future BaseClient::UploadPartCopyAsync( +std::future> BaseClient::UploadPartCopyAsync( UploadPartCopyArgs args) { return std::async(std::launch::async, [this, args = std::move(args)]() mutable { diff --git a/src/c_api.cc b/src/c_api.cc index dff64e0..7cc9905 100644 --- a/src/c_api.cc +++ b/src/c_api.cc @@ -129,17 +129,17 @@ ssize_t miniocpp_put_object(miniocpp_client* c, const char* bucket, args.part_size = 16 * 1024 * 1024L; } - minio::s3::PutObjectResponse resp = holder->client->PutObject(args); + auto resp = holder->client->PutObject(args); if (!resp) { - SetLastError(resp.Error().String()); + SetLastError(resp.error().String()); return MINIOCPP_ERR_GENERIC; } if (etag_out != nullptr) { - std::strncpy(etag_out, resp.etag.c_str(), 63); + std::strncpy(etag_out, resp->etag.c_str(), 63); etag_out[63] = '\0'; } if (checksum_out != nullptr) { - std::strncpy(checksum_out, resp.checksum_crc64nvme.c_str(), 63); + std::strncpy(checksum_out, resp->checksum_crc64nvme.c_str(), 63); checksum_out[63] = '\0'; } return static_cast(size); @@ -178,9 +178,9 @@ ssize_t miniocpp_get_object(miniocpp_client* c, const char* bucket, }; } - minio::s3::GetObjectResponse resp = holder->client->GetObject(args); + auto resp = holder->client->GetObject(args); if (!resp) { - SetLastError(resp.Error().String()); + SetLastError(resp.error().String()); return MINIOCPP_ERR_GENERIC; } return buf != nullptr ? static_cast(size) : bytes_seen; diff --git a/src/client.cc b/src/client.cc index 0f0e105..1153642 100644 --- a/src/client.cc +++ b/src/client.cc @@ -135,8 +135,7 @@ struct ScopedRDMARegistration { ListObjectsResult::ListObjectsResult(error::Error err) : failed_(true) { resp_ = std::make_shared(); - resp_->contents.push_back(Item(std::move(err))); - itr_ = resp_->contents.begin(); + itr_ = resp_->contents.end(); } ListObjectsResult::ListObjectsResult(Client* const client, @@ -178,10 +177,9 @@ void ListObjectsResult::StartPrefetch() { [client = client_, next_args = std::move(next_args)]() mutable -> std::shared_ptr { try { - GetRegionResponse resp = - client->GetRegion(next_args.bucket, next_args.region); + auto resp = client->GetRegion(next_args.bucket, next_args.region); if (resp) { - next_args.region = resp.region; + next_args.region = resp->region; if (next_args.recursive) { next_args.delimiter = ""; } else if (next_args.delimiter.empty()) { @@ -190,27 +188,39 @@ void ListObjectsResult::StartPrefetch() { if (next_args.include_versions || !next_args.version_id_marker.empty()) { - return std::make_shared( - client->ListObjectVersions( - ListObjectVersionsArgs(next_args))); + auto list_resp = client->ListObjectVersions( + ListObjectVersionsArgs(next_args)); + if (list_resp) { + return std::shared_ptr( + new ListObjectsResponse(std::move(*list_resp))); + } + return std::make_shared(); } else if (next_args.use_api_v1) { - return std::make_shared( - client->ListObjectsV1(ListObjectsV1Args(next_args))); + auto list_resp = + client->ListObjectsV1(ListObjectsV1Args(next_args)); + if (list_resp) { + return std::shared_ptr( + new ListObjectsResponse(std::move(*list_resp))); + } + return std::make_shared(); } else { - return std::make_shared( - client->ListObjectsV2(ListObjectsV2Args(next_args))); + auto list_resp = + client->ListObjectsV2(ListObjectsV2Args(next_args)); + if (list_resp) { + return std::shared_ptr( + new ListObjectsResponse(std::move(*list_resp))); + } + return std::make_shared(); } } - return std::make_shared(resp); + return std::make_shared(); } catch (const std::exception& e) { - return std::make_shared( - error::Error(std::string("prefetch failed: ") + e.what())); + return std::make_shared(); } })); } catch (const std::exception& e) { std::promise> p; - p.set_value(std::make_shared( - error::Error(std::string("failed to launch prefetch: ") + e.what()))); + p.set_value(std::make_shared()); prefetch_future_ = std::make_shared< std::shared_future>>( p.get_future()); @@ -224,17 +234,15 @@ void ListObjectsResult::Populate() { try { resp_ = prefetch_future_->get(); } catch (const std::exception& e) { - resp_ = std::make_shared( - error::Error(std::string("prefetch result failed: ") + e.what())); + resp_ = std::make_shared(); } prefetch_future_.reset(); - if (!*resp_) { + if (failed_ || resp_->contents.empty()) { failed_ = true; - resp_->contents.push_back(Item(*resp_)); } itr_ = resp_->contents.begin(); - if (*resp_ && resp_->is_truncated) { + if (!failed_ && resp_->is_truncated) { UpdatePaginationArgs(); StartPrefetch(); } @@ -242,8 +250,7 @@ void ListObjectsResult::Populate() { RemoveObjectsResult::RemoveObjectsResult(error::Error err) { done_ = true; - resp_.errors.push_back(DeleteError(err)); - itr_ = resp_.errors.begin(); + itr_ = resp_.errors.end(); } RemoveObjectsResult::RemoveObjectsResult(Client* const client, @@ -277,9 +284,9 @@ void RemoveObjectsResult::Populate() { } if (args.objects.size() != 0) { - resp_ = client_->BaseClient::RemoveObjects(args); - if (!resp_) { - resp_.errors.push_back(DeleteError(resp_)); + auto rm_resp = client_->BaseClient::RemoveObjects(args); + if (rm_resp) { + resp_ = std::move(*rm_resp); } itr_ = resp_.errors.begin(); } else { @@ -313,7 +320,7 @@ cuObjClient& Client::SharedRDMAClient() { Client::Client(BaseUrl& base_url, creds::Provider* const provider) : BaseClient(base_url, provider) {} -StatObjectResponse Client::CalculatePartCount( +Result Client::CalculatePartCount( size_t& part_count, std::list sources) { size_t object_size = 0; size_t i = 0; @@ -332,14 +339,14 @@ StatObjectResponse Client::CalculatePartCount( std::string etag; size_t size; - StatObjectResponse resp = StatObject(source); + auto resp = StatObject(source); if (!resp) { return resp; } - etag = resp.etag; - size = resp.size; + etag = resp->etag; + size = resp->size; if (error::Error err = source.BuildHeaders(size, etag)) { - return StatObjectResponse(err); + return tl::make_unexpected(err); } if (source.length.has_value()) { size = *source.length; @@ -397,16 +404,17 @@ StatObjectResponse Client::CalculatePartCount( } } - return StatObjectResponse(error::SUCCESS); + StatObjectResponse result; + return result; } -ComposeObjectResponse Client::ComposeObject(ComposeObjectArgs args, - std::string& upload_id) { +Result Client::ComposeObject(ComposeObjectArgs args, + std::string& upload_id) { size_t part_count = 0; { - StatObjectResponse resp = CalculatePartCount(part_count, args.sources); + auto resp = CalculatePartCount(part_count, args.sources); if (!resp) { - return ComposeObjectResponse(resp); + return tl::make_unexpected(resp.error()); } } @@ -422,7 +430,9 @@ ComposeObjectResponse Client::ComposeObject(ComposeObjectArgs args, coargs.sse = args.sse; coargs.source = source; - return ComposeObjectResponse(CopyObject(coargs)); + auto co_resp = CopyObject(coargs); + if (!co_resp) return tl::make_unexpected(co_resp.error()); + return ComposeObjectResponse(std::move(*co_resp)); } utils::Multimap headers = args.Headers(); @@ -434,10 +444,10 @@ ComposeObjectResponse Client::ComposeObject(ComposeObjectArgs args, cmu_args.region = args.region; cmu_args.object = args.object; cmu_args.headers = headers; - if (CreateMultipartUploadResponse resp = CreateMultipartUpload(cmu_args)) { - upload_id = resp.upload_id; + if (auto resp = CreateMultipartUpload(cmu_args)) { + upload_id = resp->upload_id; } else { - return ComposeObjectResponse(resp); + return tl::make_unexpected(resp.error()); } } @@ -484,11 +494,11 @@ ComposeObjectResponse Client::ComposeObject(ComposeObjectArgs args, upc_args.headers = headers; upc_args.upload_id = upload_id; upc_args.part_number = part_number; - UploadPartCopyResponse resp = UploadPartCopy(upc_args); + auto resp = UploadPartCopy(upc_args); if (!resp) { - return ComposeObjectResponse(resp); + return tl::make_unexpected(resp.error()); } - parts.push_back(Part(part_number, std::move(resp.etag))); + parts.push_back(Part(part_number, std::move(resp->etag))); } else { while (size > 0) { part_number++; @@ -511,11 +521,11 @@ ComposeObjectResponse Client::ComposeObject(ComposeObjectArgs args, upc_args.upload_id = upload_id; upc_args.part_number = part_number; { - UploadPartCopyResponse resp = UploadPartCopy(upc_args); + auto resp = UploadPartCopy(upc_args); if (!resp) { - return ComposeObjectResponse(resp); + return tl::make_unexpected(resp.error()); } - parts.push_back(Part(part_number, std::move(resp.etag))); + parts.push_back(Part(part_number, std::move(resp->etag))); } offset += length; size -= length; @@ -529,21 +539,23 @@ ComposeObjectResponse Client::ComposeObject(ComposeObjectArgs args, cmu_args.object = args.object; cmu_args.upload_id = upload_id; cmu_args.parts = parts; - return ComposeObjectResponse(CompleteMultipartUpload(cmu_args)); + auto cmu_resp = CompleteMultipartUpload(cmu_args); + if (!cmu_resp) return tl::make_unexpected(cmu_resp.error()); + return ComposeObjectResponse(std::move(*cmu_resp)); } -GetObjectResponse Client::GetObject(GetObjectArgs args) { +Result Client::GetObject(GetObjectArgs args) { if (error::Error err = args.Validate()) { - return GetObjectResponse(err); + return tl::make_unexpected(err); } #ifdef MINIO_CPP_RDMA if (args.buf != nullptr) { std::string region; - if (GetRegionResponse resp = GetRegion(args.bucket, args.region)) { - region = resp.region; + if (auto get_resp = GetRegion(args.bucket, args.region)) { + region = get_resp->region; } else { - return GetObjectResponse(resp); + return tl::make_unexpected(get_resp.error()); } const size_t size = *args.size; @@ -566,9 +578,9 @@ GetObjectResponse Client::GetObject(GetObjectArgs args) { rdma_client.cuMemObjPutDescriptor(args.buf); if (ret > 0) { - GetObjectResponse resp; - resp.etag = getCtx.etag; - return resp; + GetObjectResponse go_result; + go_result.etag = getCtx.etag; + return go_result; } // ret < 0 (retries exhausted) or kRDMANotSupported (server declined): // fall through to HTTP-into-buffer path below. @@ -594,8 +606,8 @@ GetObjectResponse Client::GetObject(GetObjectArgs args) { return BaseClient::GetObject(args); } -PutObjectResponse Client::PutObject(PutObjectArgs args, std::string& upload_id, - char* buf) { +Result Client::PutObject(PutObjectArgs args, + std::string& upload_id, char* buf) { utils::Multimap headers = args.Headers(); if (!headers.Contains("Content-Type")) { if (args.content_type.empty()) { @@ -670,7 +682,7 @@ PutObjectResponse Client::PutObject(PutObjectArgs args, std::string& upload_id, size_t bytes_read = 0; if (error::Error err = read_part_data(buf, bytes_read)) { - return PutObjectResponse(err); + return tl::make_unexpected(err); } std::string_view data(buf, part_size); @@ -706,11 +718,11 @@ PutObjectResponse Client::PutObject(PutObjectArgs args, std::string& upload_id, // an algorithm was declared on Create). cmu_args.headers.Add("x-amz-checksum-algorithm", "CRC64NVME"); #endif - if (CreateMultipartUploadResponse resp = - CreateMultipartUpload(cmu_args)) { - upload_id = resp.upload_id; + auto cmu_resp = CreateMultipartUpload(cmu_args); + if (cmu_resp) { + upload_id = cmu_resp->upload_id; } else { - return PutObjectResponse(resp); + return tl::make_unexpected(cmu_resp.error()); } } @@ -768,7 +780,7 @@ PutObjectResponse Client::PutObject(PutObjectArgs args, std::string& upload_id, } } - if (UploadPartResponse resp = UploadPart(up_args)) { + if (auto resp = UploadPart(up_args)) { if (args.progressfunc != nullptr) { uploaded_bytes += static_cast(data.length()); http::ProgressFunctionArgs actual_args; @@ -777,12 +789,12 @@ PutObjectResponse Client::PutObject(PutObjectArgs args, std::string& upload_id, actual_args.uploaded_bytes = uploaded_bytes; actual_args.userdata = args.progress_userdata; if (!args.progressfunc(actual_args)) { - return UploadPartResponse( + return tl::make_unexpected( error::Error("aborted by progress function")); } } // HTTP fallback leaves resp.checksum_crc64nvme empty; use the local CRC. - parts.push_back(Part(part_number, std::move(resp.etag), + parts.push_back(Part(part_number, std::move(resp->etag), std::move(up_args.checksum_crc64nvme))); } else { return resp; @@ -795,20 +807,23 @@ PutObjectResponse Client::PutObject(PutObjectArgs args, std::string& upload_id, cmu_args.object = args.object; cmu_args.upload_id = upload_id; cmu_args.parts = parts; - CompleteMultipartUploadResponse resp = CompleteMultipartUpload(cmu_args); - if (resp && args.progressfunc != nullptr) { + auto resp = CompleteMultipartUpload(cmu_args); + if (!resp) { + return tl::make_unexpected(resp.error()); + } + if (args.progressfunc != nullptr) { http::ProgressFunctionArgs actual_args; actual_args.upload_speed = upload_speed.value_or(-1.0); actual_args.userdata = args.progress_userdata; // ignore the return value as we completed the upload args.progressfunc(actual_args); } - return PutObjectResponse(resp); + return PutObjectResponse(std::move(*resp)); } -ComposeObjectResponse Client::ComposeObject(ComposeObjectArgs args) { +Result Client::ComposeObject(ComposeObjectArgs args) { if (error::Error err = args.Validate()) { - return ComposeObjectResponse(err); + return tl::make_unexpected(err); } if (args.sse != nullptr && args.sse->TlsRequired() && !base_url_.https) { @@ -817,7 +832,7 @@ ComposeObjectResponse Client::ComposeObject(ComposeObjectArgs args) { } std::string upload_id; - ComposeObjectResponse resp = ComposeObject(args, upload_id); + auto resp = ComposeObject(args, upload_id); if (!resp && !upload_id.empty()) { AbortMultipartUploadArgs amu_args; amu_args.bucket = args.bucket; @@ -830,9 +845,9 @@ ComposeObjectResponse Client::ComposeObject(ComposeObjectArgs args) { return resp; } -CopyObjectResponse Client::CopyObject(CopyObjectArgs args) { +Result Client::CopyObject(CopyObjectArgs args) { if (error::Error err = args.Validate()) { - return CopyObjectResponse(err); + return tl::make_unexpected(err); } if (args.sse != nullptr && args.sse->TlsRequired() && !base_url_.https) { @@ -848,12 +863,12 @@ CopyObjectResponse Client::CopyObject(CopyObjectArgs args) { std::string etag; size_t size; { - StatObjectResponse resp = StatObject(args.source); + auto resp = StatObject(args.source); if (!resp) { - return CopyObjectResponse(resp); + return tl::make_unexpected(resp.error()); } - etag = resp.etag; - size = resp.size; + etag = resp->etag; + size = resp->size; } if (args.source.offset.has_value() || args.source.length.has_value() || @@ -895,7 +910,9 @@ CopyObjectResponse Client::CopyObject(CopyObjectArgs args) { coargs.sse = args.sse; coargs.sources.push_back(src); - return CopyObjectResponse(ComposeObject(coargs)); + auto co_result = ComposeObject(coargs); + if (!co_result) return tl::make_unexpected(co_result.error()); + return CopyObjectResponse(std::move(*co_result)); } utils::Multimap headers; @@ -912,10 +929,10 @@ CopyObjectResponse Client::CopyObject(CopyObjectArgs args) { headers.AddAll(args.source.CopyHeaders()); std::string region; - if (GetRegionResponse resp = GetRegion(args.bucket, args.region)) { - region = resp.region; + if (auto get_resp = GetRegion(args.bucket, args.region)) { + region = get_resp->region; } else { - return CopyObjectResponse(resp); + return tl::make_unexpected(get_resp.error()); } Request req(http::Method::kPut, region, base_url_, args.extra_headers, @@ -924,21 +941,21 @@ CopyObjectResponse Client::CopyObject(CopyObjectArgs args) { req.object_name = args.object; req.headers.AddAll(headers); - Response response = Execute(req); + auto response = Execute(req); if (!response) { - return CopyObjectResponse(response); + return tl::make_unexpected(response.error()); } CopyObjectResponse resp; - resp.etag = utils::Trim(response.headers.GetFront("etag"), '"'); - resp.version_id = response.headers.GetFront("x-amz-version-id"); + resp.etag = utils::Trim(response->headers.GetFront("etag"), '"'); + resp.version_id = response->headers.GetFront("x-amz-version-id"); return resp; } -DownloadObjectResponse Client::DownloadObject(DownloadObjectArgs args) { +Result Client::DownloadObject(DownloadObjectArgs args) { if (error::Error err = args.Validate()) { - return DownloadObjectResponse(err); + return tl::make_unexpected(err); } if (args.ssec != nullptr && !base_url_.https) { @@ -954,11 +971,11 @@ DownloadObjectResponse Client::DownloadObject(DownloadObjectArgs args) { soargs.object = args.object; soargs.version_id = args.version_id; soargs.ssec = args.ssec; - StatObjectResponse resp = StatObject(soargs); + auto resp = StatObject(soargs); if (!resp) { - return DownloadObjectResponse(resp); + return tl::make_unexpected(resp.error()); } - etag = resp.etag; + etag = resp->etag; } std::string temp_filename = @@ -970,10 +987,10 @@ DownloadObjectResponse Client::DownloadObject(DownloadObjectArgs args) { } std::string region; - if (GetRegionResponse resp = GetRegion(args.bucket, args.region)) { - region = resp.region; + if (auto get_resp = GetRegion(args.bucket, args.region)) { + region = get_resp->region; } else { - return DownloadObjectResponse(resp); + return tl::make_unexpected(get_resp.error()); } Request req(http::Method::kGet, region, base_url_, args.extra_headers, @@ -990,12 +1007,13 @@ DownloadObjectResponse Client::DownloadObject(DownloadObjectArgs args) { req.progressfunc = args.progressfunc; req.progress_userdata = args.progress_userdata; - Response response = Execute(req); + auto response = Execute(req); fout.close(); if (response) { std::filesystem::rename(temp_filename, args.filename); + return DownloadObjectResponse(std::move(*response)); } - return DownloadObjectResponse(response); + return tl::make_unexpected(response.error()); } ListObjectsResult Client::ListObjects(ListObjectsArgs args) { @@ -1005,9 +1023,9 @@ ListObjectsResult Client::ListObjects(ListObjectsArgs args) { return ListObjectsResult(this, std::move(args)); } -PutObjectResponse Client::PutObject(PutObjectArgs args) { +Result Client::PutObject(PutObjectArgs args) { if (error::Error err = args.Validate()) { - return PutObjectResponse(err); + return tl::make_unexpected(err); } if (args.sse != nullptr && args.sse->TlsRequired() && !base_url_.https) { @@ -1021,10 +1039,10 @@ PutObjectResponse Client::PutObject(PutObjectArgs args) { // HTTP upload from the same buffer if RDMA declines. if (args.buf != nullptr) { std::string region; - if (GetRegionResponse resp = GetRegion(args.bucket, args.region)) { - region = resp.region; + if (auto get_resp = GetRegion(args.bucket, args.region)) { + region = get_resp->region; } else { - return PutObjectResponse(resp); + return tl::make_unexpected(get_resp.error()); } const size_t size = *args.size; @@ -1142,7 +1160,7 @@ PutObjectResponse Client::PutObject(PutObjectArgs args) { unsigned int part_number; std::string checksum_crc64nvme; size_t part_bytes; - std::future future; + std::future> future; }; std::deque inflight; @@ -1219,19 +1237,12 @@ PutObjectResponse Client::PutObject(PutObjectArgs args) { if (inflight.size() >= max_inflight) { InflightPart ip = std::move(inflight.front()); inflight.pop_front(); - UploadPartResponse resp; - try { - resp = ip.future.get(); - } catch (const std::exception& e) { - first_err = - error::Error(std::string("upload part failed: ") + e.what()); - break; - } - if (!resp) { - first_err = resp.Error(); + auto up_resp = ip.future.get(); + if (!up_resp) { + first_err = up_resp.error(); break; } - parts.push_back(Part(ip.part_number, std::move(resp.etag), + parts.push_back(Part(ip.part_number, std::move(up_resp->etag), std::move(ip.checksum_crc64nvme))); if (!report_progress(ip.part_bytes)) { break; @@ -1274,11 +1285,10 @@ PutObjectResponse Client::PutObject(PutObjectArgs args) { #ifdef MINIO_CPP_RDMA cmu_args.headers.Add("x-amz-checksum-algorithm", "CRC64NVME"); #endif - if (CreateMultipartUploadResponse resp = - CreateMultipartUpload(cmu_args)) { - upload_id = resp.upload_id; + if (auto cmu_resp = CreateMultipartUpload(cmu_args)) { + upload_id = cmu_resp->upload_id; } else { - first_err = resp.Error(); + first_err = cmu_resp.error(); break; } } @@ -1336,20 +1346,12 @@ PutObjectResponse Client::PutObject(PutObjectArgs args) { while (!inflight.empty()) { InflightPart ip = std::move(inflight.front()); inflight.pop_front(); - UploadPartResponse resp; - try { - resp = ip.future.get(); - } catch (const std::exception& e) { - if (!first_err) - first_err = - error::Error(std::string("upload part failed: ") + e.what()); - continue; - } - if (!resp) { - if (!first_err) first_err = resp.Error(); + auto drain_resp = ip.future.get(); + if (!drain_resp) { + if (!first_err) first_err = drain_resp.error(); continue; } - parts.push_back(Part(ip.part_number, std::move(resp.etag), + parts.push_back(Part(ip.part_number, std::move(drain_resp->etag), std::move(ip.checksum_crc64nvme))); if (!first_err) report_progress(ip.part_bytes); } @@ -1363,7 +1365,7 @@ PutObjectResponse Client::PutObject(PutObjectArgs args) { amu_args.upload_id = upload_id; AbortMultipartUpload(amu_args); } - return PutObjectResponse(first_err); + return tl::make_unexpected(first_err); } // Complete multipart upload. @@ -1373,8 +1375,7 @@ PutObjectResponse Client::PutObject(PutObjectArgs args) { cmu_args.object = args.object; cmu_args.upload_id = upload_id; cmu_args.parts = parts; - CompleteMultipartUploadResponse cmu_resp = - CompleteMultipartUpload(cmu_args); + auto cmu_resp = CompleteMultipartUpload(cmu_args); if (cmu_resp && args.progressfunc != nullptr) { http::ProgressFunctionArgs actual_args; actual_args.upload_speed = upload_speed.value_or(-1.0); @@ -1389,7 +1390,10 @@ PutObjectResponse Client::PutObject(PutObjectArgs args) { amu_args.upload_id = upload_id; AbortMultipartUpload(amu_args); } - return PutObjectResponse(cmu_resp); + if (!cmu_resp) { + return tl::make_unexpected(cmu_resp.error()); + } + return PutObjectResponse(std::move(*cmu_resp)); } void* raw = nullptr; @@ -1423,7 +1427,7 @@ PutObjectResponse Client::PutObject(PutObjectArgs args) { #endif std::string upload_id; - PutObjectResponse resp = PutObject(args, upload_id, buf); + auto resp = PutObject(args, upload_id, buf); if (!resp && !upload_id.empty()) { AbortMultipartUploadArgs amu_args; @@ -1437,9 +1441,9 @@ PutObjectResponse Client::PutObject(PutObjectArgs args) { return resp; } -UploadObjectResponse Client::UploadObject(UploadObjectArgs args) { +Result Client::UploadObject(UploadObjectArgs args) { if (error::Error err = args.Validate()) { - return UploadObjectResponse(err); + return tl::make_unexpected(err); } std::ifstream file; @@ -1467,9 +1471,12 @@ UploadObjectResponse Client::UploadObject(UploadObjectArgs args) { po_args.progressfunc = std::move(args.progressfunc); po_args.progress_userdata = std::move(args.progress_userdata); - PutObjectResponse resp = PutObject(std::move(po_args)); + auto resp = PutObject(std::move(po_args)); file.close(); - return UploadObjectResponse(resp); + if (resp) { + return UploadObjectResponse(std::move(*resp)); + } + return tl::make_unexpected(resp.error()); } RemoveObjectsResult Client::RemoveObjects(RemoveObjectsArgs args) { @@ -1481,7 +1488,7 @@ RemoveObjectsResult Client::RemoveObjects(RemoveObjectsArgs args) { // ---- Async overloads ---- -std::future Client::ComposeObjectAsync( +std::future> Client::ComposeObjectAsync( ComposeObjectArgs args) { return std::async(std::launch::async, [this, args = std::move(args)]() mutable { @@ -1489,14 +1496,15 @@ std::future Client::ComposeObjectAsync( }); } -std::future Client::CopyObjectAsync(CopyObjectArgs args) { +std::future> Client::CopyObjectAsync( + CopyObjectArgs args) { return std::async(std::launch::async, [this, args = std::move(args)]() mutable { return CopyObject(std::move(args)); }); } -std::future Client::DownloadObjectAsync( +std::future> Client::DownloadObjectAsync( DownloadObjectArgs args) { return std::async(std::launch::async, [this, args = std::move(args)]() mutable { @@ -1504,7 +1512,8 @@ std::future Client::DownloadObjectAsync( }); } -std::future Client::GetObjectAsync(GetObjectArgs args) { +std::future> Client::GetObjectAsync( + GetObjectArgs args) { return std::async(std::launch::async, [this, args = std::move(args)]() mutable { return Client::GetObject(std::move(args)); @@ -1518,14 +1527,15 @@ std::future Client::ListObjectsAsync(ListObjectsArgs args) { }); } -std::future Client::PutObjectAsync(PutObjectArgs args) { +std::future> Client::PutObjectAsync( + PutObjectArgs args) { return std::async(std::launch::async, [this, args = std::move(args)]() mutable { return PutObject(std::move(args)); }); } -std::future Client::UploadObjectAsync( +std::future> Client::UploadObjectAsync( UploadObjectArgs args) { return std::async(std::launch::async, [this, args = std::move(args)]() mutable { diff --git a/src/credentials.cc b/src/credentials.cc index 1637993..c352133 100644 --- a/src/credentials.cc +++ b/src/credentials.cc @@ -22,6 +22,7 @@ #include #include "miniocpp/error.h" +#include "miniocpp/result.h" #include "miniocpp/utils.h" namespace minio::creds { @@ -33,12 +34,12 @@ bool expired(const utils::UtcTime& expiration) { return expiration < now; } -Credentials Credentials::ParseXML(std::string_view data, - const std::string& root) { +Result Credentials::ParseXML(std::string_view data, + const std::string& root) { pugi::xml_document xdoc; pugi::xml_parse_result result = xdoc.load_string(data.data()); if (!result) { - return error::make("unable to parse XML"); + return tl::make_unexpected(error::Error("unable to parse XML")); } auto credentials = xdoc.select_node((root + "/Credentials").c_str()); diff --git a/src/providers.cc b/src/providers.cc index b104da4..93a3aa4 100644 --- a/src/providers.cc +++ b/src/providers.cc @@ -92,7 +92,7 @@ Credentials ChainedProvider::Fetch() { if (creds_) return creds_; } - return error::make("All providers fail to fetch credentials"); + return Credentials{error::Error("All providers fail to fetch credentials")}; } StaticProvider::StaticProvider(std::string access_key, std::string secret_key, @@ -154,7 +154,7 @@ AwsConfigProvider::AwsConfigProvider(std::string filename, INIReader reader(filename); if (reader.ParseError() < 0) { - this->creds_ = error::make("unable to read " + filename); + this->creds_ = Credentials{error::Error("unable to read " + filename)}; } else { this->creds_ = Credentials{error::SUCCESS, reader.Get(profile, "aws_access_key_id", ""), @@ -186,14 +186,14 @@ MinioClientConfigProvider::MinioClientConfigProvider(std::string filename, aliases = json["aliases"]; } else { this->creds_ = - error::make("invalid configuration in file " + filename); + Credentials{error::Error("invalid configuration in file " + filename)}; return; } if (!aliases.contains(alias)) { - this->creds_ = error::make( + this->creds_ = Credentials{error::Error( "alias " + alias + " not found in MinIO client configuration file " + - filename); + filename)}; return; } @@ -259,7 +259,12 @@ Credentials AssumeRoleProvider::Fetch() { if (!resp) { creds_ = Credentials{resp.Error()}; } else { - creds_ = Credentials::ParseXML(resp.body, "AssumeRoleResult"); + auto parse_res = Credentials::ParseXML(resp.body, "AssumeRoleResult"); + if (parse_res) { + creds_ = std::move(*parse_res); + } else { + creds_ = Credentials{parse_res.error()}; + } } return creds_; @@ -323,9 +328,14 @@ Credentials WebIdentityClientGrantsProvider::Fetch() { if (!resp) { creds_ = Credentials{resp.Error()}; } else { - creds_ = Credentials::ParseXML( + auto parse_res = Credentials::ParseXML( resp.body, IsWebIdentity() ? "AssumeRoleWithWebIdentityResult" : "AssumeRoleWithClientGrantsResult"); + if (parse_res) { + creds_ = std::move(*parse_res); + } else { + creds_ = Credentials{parse_res.error()}; + } } return creds_; } @@ -430,9 +440,9 @@ Credentials IamAwsProvider::fetch(http::Url url) { nlohmann::json json = nlohmann::json::parse(resp.body); std::string code = json.value("Code", "Success"); if (code != "Success") { - return error::make(url.String() + " failed with code " + code + + return Credentials{error::Error(url.String() + " failed with code " + code + " and message " + - json.value("Message", "")); + json.value("Message", ""))}; } std::string expiration = json["Expiration"]; @@ -486,7 +496,13 @@ Credentials LdapIdentityProvider::Fetch() { http::Response resp = req.Execute(); if (!resp) return Credentials{resp.Error()}; - creds_ = Credentials::ParseXML(resp.body, "AssumeRoleWithLDAPIdentityResult"); + auto parse_res = + Credentials::ParseXML(resp.body, "AssumeRoleWithLDAPIdentityResult"); + if (parse_res) { + creds_ = std::move(*parse_res); + } else { + creds_ = Credentials{parse_res.error()}; + } return creds_; } @@ -535,7 +551,13 @@ Credentials CertificateIdentityProvider::Fetch() { http::Response resp = req.Execute(); if (!resp) return Credentials{resp.Error()}; - creds_ = Credentials::ParseXML(resp.body, "AssumeRoleWithCertificateResult"); + auto parse_res = + Credentials::ParseXML(resp.body, "AssumeRoleWithCertificateResult"); + if (parse_res) { + creds_ = std::move(*parse_res); + } else { + creds_ = Credentials{parse_res.error()}; + } return creds_; } diff --git a/src/response.cc b/src/response.cc index 05a48fb..ffdfc64 100644 --- a/src/response.cc +++ b/src/response.cc @@ -35,20 +35,8 @@ Response::Response() {} Response::~Response() {} -error::Error Response::Error() const { - if (err_) return err_; - if (!code.empty()) { - return error::Error(code + ": " + message); - } - if (status_code && (status_code < 200 || status_code > 299)) { - return error::Error("failed with HTTP status code " + - std::to_string(status_code)); - } - return error::SUCCESS; -} - -Response Response::ParseXML(std::string_view data, int status_code, - utils::Multimap headers) { +Result Response::ParseXML(std::string_view data, int status_code, + utils::Multimap headers) { Response resp; resp.status_code = status_code; resp.headers = headers; @@ -56,8 +44,7 @@ Response Response::ParseXML(std::string_view data, int status_code, pugi::xml_document xdoc; pugi::xml_parse_result result = xdoc.load_buffer(data.data(), data.size()); if (!result) { - resp.err_ = error::Error("unable to parse XML; " + std::string(data)); - return resp; + return error::make("unable to parse XML; " + std::string(data)); } auto root = xdoc.select_node("/Error"); @@ -87,7 +74,8 @@ Response Response::ParseXML(std::string_view data, int status_code, return resp; } -ListBucketsResponse ListBucketsResponse::ParseXML(std::string_view data) { +Result ListBucketsResponse::ParseXML( + std::string_view data) { std::list buckets; pugi::xml_document xdoc; @@ -114,8 +102,9 @@ ListBucketsResponse ListBucketsResponse::ParseXML(std::string_view data) { return ListBucketsResponse(buckets); } -CompleteMultipartUploadResponse CompleteMultipartUploadResponse::ParseXML( - std::string_view data, std::string version_id) { +Result +CompleteMultipartUploadResponse::ParseXML(std::string_view data, + std::string version_id) { CompleteMultipartUploadResponse resp; pugi::xml_document xdoc; @@ -156,8 +145,8 @@ CompleteMultipartUploadResponse CompleteMultipartUploadResponse::ParseXML( return resp; } -ListObjectsResponse ListObjectsResponse::ParseXML(std::string_view data, - bool version) { +Result ListObjectsResponse::ParseXML(std::string_view data, + bool version) { ListObjectsResponse resp; auto xdoc = std::make_shared(); @@ -344,7 +333,8 @@ ListObjectsResponse ListObjectsResponse::ParseXML(std::string_view data, return resp; } -RemoveObjectsResponse RemoveObjectsResponse::ParseXML(std::string_view data) { +Result RemoveObjectsResponse::ParseXML( + std::string_view data) { RemoveObjectsResponse resp; pugi::xml_document xdoc; @@ -400,7 +390,7 @@ RemoveObjectsResponse RemoveObjectsResponse::ParseXML(std::string_view data) { return resp; } -GetBucketNotificationResponse GetBucketNotificationResponse::ParseXML( +Result GetBucketNotificationResponse::ParseXML( std::string_view data) { NotificationConfig config; @@ -495,7 +485,7 @@ GetBucketNotificationResponse GetBucketNotificationResponse::ParseXML( return GetBucketNotificationResponse(config); } -GetBucketEncryptionResponse GetBucketEncryptionResponse::ParseXML( +Result GetBucketEncryptionResponse::ParseXML( std::string_view data) { SseConfig config; @@ -517,7 +507,7 @@ GetBucketEncryptionResponse GetBucketEncryptionResponse::ParseXML( return GetBucketEncryptionResponse(config); } -GetBucketReplicationResponse GetBucketReplicationResponse::ParseXML( +Result GetBucketReplicationResponse::ParseXML( std::string_view data) { ReplicationConfig config; @@ -683,7 +673,7 @@ GetBucketReplicationResponse GetBucketReplicationResponse::ParseXML( return GetBucketReplicationResponse(config); } -GetBucketLifecycleResponse GetBucketLifecycleResponse::ParseXML( +Result GetBucketLifecycleResponse::ParseXML( std::string_view data) { LifecycleConfig config; @@ -811,7 +801,8 @@ GetBucketLifecycleResponse GetBucketLifecycleResponse::ParseXML( return GetBucketLifecycleResponse(config); } -GetBucketTagsResponse GetBucketTagsResponse::ParseXML(std::string_view data) { +Result GetBucketTagsResponse::ParseXML( + std::string_view data) { std::map map; pugi::xml_document xdoc; @@ -836,7 +827,8 @@ GetBucketTagsResponse GetBucketTagsResponse::ParseXML(std::string_view data) { return map; } -GetObjectTagsResponse GetObjectTagsResponse::ParseXML(std::string_view data) { +Result GetObjectTagsResponse::ParseXML( + std::string_view data) { std::map map; pugi::xml_document xdoc; diff --git a/src/select.cc b/src/select.cc index 9538afc..ce6c4db 100644 --- a/src/select.cc +++ b/src/select.cc @@ -124,7 +124,7 @@ bool SelectHandler::process(const http::DataFunctionArgs& /* args */, done_ = true; std::string msg("prelude CRC mismatch; expected: "); msg += std::to_string(expected) + ", got: " + std::to_string(got); - result_func_(error::make(msg)); + result_func_(SelectResult(error::Error(msg))); return false; } total_length_ = utils::Int(prelude_.substr(0, 4)); @@ -142,7 +142,7 @@ bool SelectHandler::process(const http::DataFunctionArgs& /* args */, done_ = true; std::string msg("message CRC mismatch; expected: "); msg += std::to_string(expected) + ", got: " + std::to_string(got); - result_func_(error::make(msg)); + result_func_(SelectResult(error::Error(msg))); return false; } } @@ -159,8 +159,8 @@ bool SelectHandler::process(const http::DataFunctionArgs& /* args */, if (headers[":message-type"] == "error") { done_ = true; - result_func_(error::make(headers[":error-code"] + ": " + - headers[":error-message"])); + result_func_(SelectResult(error::Error(headers[":error-code"] + ": " + + headers[":error-message"]))); return false; } @@ -186,7 +186,7 @@ bool SelectHandler::process(const http::DataFunctionArgs& /* args */, if (!result) { done_ = true; result_func_( - error::make("unable to parse XML; " + payload)); + SelectResult(error::Error("unable to parse XML; " + payload))); return false; } @@ -226,8 +226,8 @@ bool SelectHandler::process(const http::DataFunctionArgs& /* args */, } done_ = true; - result_func_(error::make(std::string("unknown event-type ") + - headers[":event-type"])); + result_func_(SelectResult(error::Error(std::string("unknown event-type ") + + headers[":event-type"]))); return false; } diff --git a/tests/tests.cc b/tests/tests.cc index 6eb3c54..824fc59 100644 --- a/tests/tests.cc +++ b/tests/tests.cc @@ -21,7 +21,10 @@ #include #include #include +#include #include + +using minio::Result; #include #include @@ -121,44 +124,44 @@ class Tests { bucket_name_ = RandBucketName(); minio::s3::MakeBucketArgs args; args.bucket = bucket_name_; - minio::s3::MakeBucketResponse resp = client_.MakeBucket(args); + auto resp = client_.MakeBucket(args); if (!resp) { - throw std::runtime_error("MakeBucket(): " + resp.Error().String()); + throw std::runtime_error("MakeBucket(): " + resp.error().String()); } } ~Tests() noexcept(false) { minio::s3::RemoveBucketArgs args; args.bucket = bucket_name_; - minio::s3::RemoveBucketResponse resp = client_.RemoveBucket(args); + auto resp = client_.RemoveBucket(args); if (!resp) { - throw std::runtime_error("RemoveBucket(): " + resp.Error().String()); + throw std::runtime_error("RemoveBucket(): " + resp.error().String()); } } void MakeBucket(std::string bucket_name) noexcept(false) { minio::s3::MakeBucketArgs args; args.bucket = bucket_name; - minio::s3::MakeBucketResponse resp = client_.MakeBucket(args); + auto resp = client_.MakeBucket(args); if (resp) return; - throw MakeBucketError("MakeBucket(): " + resp.Error().String()); + throw MakeBucketError("MakeBucket(): " + resp.error().String()); } void RemoveBucket(std::string bucket_name) noexcept(false) { minio::s3::RemoveBucketArgs args; args.bucket = bucket_name; - minio::s3::RemoveBucketResponse resp = client_.RemoveBucket(args); + auto resp = client_.RemoveBucket(args); if (resp) return; - throw RemoveBucketError("RemoveBucket(): " + resp.Error().String()); + throw RemoveBucketError("RemoveBucket(): " + resp.error().String()); } void RemoveObject(std::string bucket_name, std::string object_name) { minio::s3::RemoveObjectArgs args; args.bucket = bucket_name; args.object = object_name; - minio::s3::RemoveObjectResponse resp = client_.RemoveObject(args); + auto resp = client_.RemoveObject(args); if (!resp) { - throw std::runtime_error("RemoveObject(): " + resp.Error().String()); + throw std::runtime_error("RemoveObject(): " + resp.error().String()); } } @@ -180,12 +183,13 @@ class Tests { return true; }; - minio::s3::RemoveObjectsResult result = client_.RemoveObjects(args); + auto result = client_.RemoveObjects(args); std::string msg; for (; result; result++) { - minio::s3::DeleteError err = *result; - if (!err) { - throw std::runtime_error("RemoveObjects(): " + err.Error().String()); + auto err = *result; + if (!err.code.empty() || !err.message.empty()) { + throw std::runtime_error("RemoveObjects(): " + err.code + ": " + + err.message); } if (msg.empty()) msg = "unable to remove object(s)"; @@ -219,11 +223,11 @@ class Tests { MakeBucket(bucket_name); minio::s3::BucketExistsArgs args; args.bucket = bucket_name; - minio::s3::BucketExistsResponse resp = client_.BucketExists(args); + auto resp = client_.BucketExists(args); if (!resp) { - throw BucketExistsError("BucketExists(): " + resp.Error().String()); + throw BucketExistsError("BucketExists(): " + resp.error().String()); } - if (!resp.exist) { + if (!resp->exist) { throw std::runtime_error("BucketExists(): expected: true; got: false"); } RemoveBucket(bucket_name); @@ -246,13 +250,13 @@ class Tests { bucket_names.push_back(bucket_name); } - minio::s3::ListBucketsResponse resp = client_.ListBuckets(); + auto resp = client_.ListBuckets(); if (!resp) { - throw std::runtime_error("ListBuckets(): " + resp.Error().String()); + throw std::runtime_error("ListBuckets(): " + resp.error().String()); } std::size_t c = 0; - for (auto& bucket : resp.buckets) { + for (auto& bucket : resp->buckets) { if (std::find(bucket_names.begin(), bucket_names.end(), bucket.name) != bucket_names.end()) { c++; @@ -280,22 +284,22 @@ class Tests { minio::s3::PutObjectArgs args(ss, static_cast(data.length()), 0); args.bucket = bucket_name_; args.object = object_name; - minio::s3::PutObjectResponse resp = client_.PutObject(args); + auto resp = client_.PutObject(args); if (!resp) { - throw std::runtime_error("PutObject(): " + resp.Error().String()); + throw std::runtime_error("PutObject(): " + resp.error().String()); } try { minio::s3::StatObjectArgs args; args.bucket = bucket_name_; args.object = object_name; - minio::s3::StatObjectResponse resp = client_.StatObject(args); + auto resp = client_.StatObject(args); if (!resp) { - throw std::runtime_error("StatObject(): " + resp.Error().String()); + throw std::runtime_error("StatObject(): " + resp.error().String()); } - if (resp.size != data.length()) { + if (resp->size != data.length()) { throw std::runtime_error( "StatObject(): expected: " + std::to_string(data.length()) + - "; got: " + std::to_string(resp.size)); + "; got: " + std::to_string(resp->size)); } RemoveObject(bucket_name_, object_name); } catch (const std::runtime_error&) { @@ -313,9 +317,9 @@ class Tests { minio::s3::PutObjectArgs args(ss, static_cast(data.length()), 0); args.bucket = bucket_name_; args.object = object_name; - minio::s3::PutObjectResponse resp = client_.PutObject(args); + auto resp = client_.PutObject(args); if (!resp) { - throw std::runtime_error("PutObject(): " + resp.Error().String()); + throw std::runtime_error("PutObject(): " + resp.error().String()); } RemoveObject(bucket_name_, object_name); } @@ -330,9 +334,9 @@ class Tests { minio::s3::PutObjectArgs args(ss, static_cast(data.length()), 0); args.bucket = bucket_name_; args.object = object_name; - minio::s3::PutObjectResponse resp = client_.PutObject(args); + auto resp = client_.PutObject(args); if (!resp) { - throw std::runtime_error("PutObject(): " + resp.Error().String()); + throw std::runtime_error("PutObject(): " + resp.error().String()); } try { @@ -341,9 +345,9 @@ class Tests { args.bucket = bucket_name_; args.object = object_name; args.filename = filename; - minio::s3::DownloadObjectResponse resp = client_.DownloadObject(args); + auto resp = client_.DownloadObject(args); if (!resp) { - throw std::runtime_error("DownloadObject(): " + resp.Error().String()); + throw std::runtime_error("DownloadObject(): " + resp.error().String()); } std::ifstream file(filename); @@ -376,9 +380,9 @@ class Tests { minio::s3::PutObjectArgs args(ss, static_cast(data.length()), 0); args.bucket = bucket_name_; args.object = object_name; - minio::s3::PutObjectResponse resp = client_.PutObject(args); + auto resp = client_.PutObject(args); if (!resp) { - throw std::runtime_error("PutObject(): " + resp.Error().String()); + throw std::runtime_error("PutObject(): " + resp.error().String()); } try { @@ -391,9 +395,9 @@ class Tests { content += args.datachunk; return true; }; - minio::s3::GetObjectResponse resp = client_.GetObject(args); + auto resp = client_.GetObject(args); if (!resp) { - throw std::runtime_error("GetObject(): " + resp.Error().String()); + throw std::runtime_error("GetObject(): " + resp.error().String()); } if (data != content) { throw std::runtime_error("GetObject(): expected: " + data + @@ -417,9 +421,9 @@ class Tests { minio::s3::PutObjectArgs args(ss, 0, 0); args.bucket = bucket_name_; args.object = object_name; - minio::s3::PutObjectResponse resp = client_.PutObject(args); + auto resp = client_.PutObject(args); if (!resp) { - throw std::runtime_error("PutObject(): " + resp.Error().String()); + throw std::runtime_error("PutObject(): " + resp.error().String()); } object_names.push_back(object_name); } @@ -427,11 +431,11 @@ class Tests { std::size_t c = 0; minio::s3::ListObjectsArgs args; args.bucket = bucket_name_; - minio::s3::ListObjectsResult result = client_.ListObjects(args); + auto result = client_.ListObjects(args); for (; result; result++) { - minio::s3::Item item = *result; - if (!item) { - throw std::runtime_error("ListObjects(): " + item.Error().String()); + auto item = *result; + if (item.name.empty()) { + throw std::runtime_error("ListObjects(): empty item"); } if (std::find(object_names.begin(), object_names.end(), item.name) != object_names.end()) { @@ -466,9 +470,9 @@ class Tests { 0); args.bucket = bucket_name_; args.object = object_name; - minio::s3::PutObjectResponse resp = client_.PutObject(args); + auto resp = client_.PutObject(args); if (!resp) { - throw std::runtime_error("PutObject(): " + resp.Error().String()); + throw std::runtime_error("PutObject(): " + resp.error().String()); } RemoveObject(bucket_name_, object_name); } @@ -480,12 +484,12 @@ class Tests { minio::s3::PutObjectArgs args(stream, static_cast(size), 0); args.bucket = bucket_name_; args.object = object_name; - minio::s3::PutObjectResponse resp = client_.PutObject(args); + auto resp = client_.PutObject(args); if (!resp) { throw std::runtime_error(" PutObject(): " + - resp.Error().String()); + resp.error().String()); } - if (resp.etag == "") { + if (resp->etag == "") { throw std::runtime_error(" PutObject(): etag is missing"); } RemoveObject(bucket_name_, object_name); @@ -502,9 +506,9 @@ class Tests { minio::s3::PutObjectArgs args(ss, static_cast(data.length()), 0); args.bucket = bucket_name_; args.object = src_object_name; - minio::s3::PutObjectResponse resp = client_.PutObject(args); + auto resp = client_.PutObject(args); if (!resp) { - throw std::runtime_error("PutObject(): " + resp.Error().String()); + throw std::runtime_error("PutObject(): " + resp.error().String()); } try { @@ -515,9 +519,9 @@ class Tests { args.bucket = bucket_name_; args.object = object_name; args.source = source; - minio::s3::CopyObjectResponse resp = client_.CopyObject(args); + auto resp = client_.CopyObject(args); if (!resp) { - throw std::runtime_error("CopyObject(): " + resp.Error().String()); + throw std::runtime_error("CopyObject(): " + resp.error().String()); } RemoveObject(bucket_name_, src_object_name); RemoveObject(bucket_name_, object_name); @@ -542,9 +546,9 @@ class Tests { args.bucket = bucket_name_; args.object = object_name; args.filename = filename; - minio::s3::UploadObjectResponse resp = client_.UploadObject(args); + auto resp = client_.UploadObject(args); if (!resp) { - throw std::runtime_error("UploadObject(): " + resp.Error().String()); + throw std::runtime_error("UploadObject(): " + resp.error().String()); } std::filesystem::remove(filename); RemoveObject(bucket_name_, object_name); @@ -561,9 +565,9 @@ class Tests { minio::s3::PutObjectArgs args(ss, 0, 0); args.bucket = bucket_name_; args.object = object_name; - minio::s3::PutObjectResponse resp = client_.PutObject(args); + auto resp = client_.PutObject(args); if (!resp) { - throw std::runtime_error("PutObject(): " + resp.Error().String()); + throw std::runtime_error("PutObject(): " + resp.error().String()); } object_names.push_back(object_name); } @@ -590,9 +594,9 @@ class Tests { 0); args.bucket = bucket_name_; args.object = object_name; - minio::s3::PutObjectResponse resp = client_.PutObject(args); + auto resp = client_.PutObject(args); if (!resp) { - throw std::runtime_error("PutObject(): " + resp.Error().String()); + throw std::runtime_error("PutObject(): " + resp.error().String()); } std::string expression = "select * from S3Object"; @@ -602,7 +606,7 @@ class Tests { csv_input.file_header_info = std::make_shared(file_header_info); minio::s3::CsvOutputSerialization csv_output; - minio::s3::QuoteFields quote_fields = minio::s3::QuoteFields::kAsNeeded; + auto quote_fields = minio::s3::QuoteFields::kAsNeeded; csv_output.quote_fields = std::make_shared(quote_fields); minio::s3::SelectRequest request(expression, &csv_input, &csv_output); @@ -620,17 +624,17 @@ class Tests { minio::s3::SelectObjectContentArgs args(request, func); args.bucket = bucket_name_; args.object = object_name; - minio::s3::SelectObjectContentResponse resp = - client_.SelectObjectContent(args); + auto resp = client_.SelectObjectContent(args); if (!resp) { - if (resp.code == "MethodNotAllowed") { + if (resp.error().String().find("MethodNotAllowed") != + std::string::npos) { std::cout << " skipped: server does not implement S3 Select" << std::endl; RemoveObject(bucket_name_, object_name); return; } throw std::runtime_error("SelectObjectContent(): " + - resp.Error().String()); + resp.error().String()); } if (records != data) { throw std::runtime_error("expected: " + data + ", got: " + records); @@ -655,11 +659,10 @@ class Tests { records.insert(records.end(), values.begin(), values.end()); return false; }; - minio::s3::ListenBucketNotificationResponse resp = - client_.ListenBucketNotification(args); + auto resp = client_.ListenBucketNotification(args); if (!resp) { throw std::runtime_error("ListenBucketNotification(): " + - resp.Error().String()); + resp.error().String()); } }}; @@ -673,9 +676,9 @@ class Tests { 0); args.bucket = bucket_name_; args.object = object_name; - minio::s3::PutObjectResponse resp = client_.PutObject(args); + auto resp = client_.PutObject(args); if (!resp) { - throw std::runtime_error("PutObject(): " + resp.Error().String()); + throw std::runtime_error("PutObject(): " + resp.error().String()); } task.join(); @@ -685,7 +688,7 @@ class Tests { "ListenBucketNotification(): records length: expected: 1, got: 0"); } - minio::s3::NotificationRecord record = records.front(); + auto record = records.front(); if (record.event_name != "s3:ObjectCreated:Put") { throw std::runtime_error( "ListenBucketNotification(): record.event_name: expected: " @@ -745,11 +748,11 @@ class Tests { args.object = object_name; args.max_inflight_parts = max_inflight; - minio::s3::PutObjectResponse resp = client_.PutObject(args); + auto resp = client_.PutObject(args); if (!resp) { remove_object_best_effort(object_name); throw std::runtime_error("PutObject(" + label + - "): " + resp.Error().String()); + "): " + resp.error().String()); } } @@ -765,10 +768,10 @@ class Tests { return true; }; - minio::s3::GetObjectResponse get_resp = client_.GetObject(gargs); + auto get_resp = client_.GetObject(gargs); if (!get_resp) { throw std::runtime_error("GetObject(" + label + - "): " + get_resp.Error().String()); + "): " + get_resp.error().String()); } std::string got_md5 = minio::utils::Md5sumHash(content); @@ -805,10 +808,10 @@ class Tests { minio::s3::MakeBucketArgs args; args.bucket = bucket_name; auto make_fut = client_.MakeBucketAsync(args); - minio::s3::MakeBucketResponse make_resp = make_fut.get(); + auto make_resp = make_fut.get(); if (!make_resp) { throw std::runtime_error("MakeBucketAsync(): " + - make_resp.Error().String()); + make_resp.error().String()); } } @@ -816,12 +819,12 @@ class Tests { minio::s3::BucketExistsArgs args; args.bucket = bucket_name; auto exists_fut = client_.BucketExistsAsync(args); - minio::s3::BucketExistsResponse exists_resp = exists_fut.get(); + auto exists_resp = exists_fut.get(); if (!exists_resp) { throw std::runtime_error("BucketExistsAsync(): " + - exists_resp.Error().String()); + exists_resp.error().String()); } - if (!exists_resp.exist) { + if (!exists_resp->exist) { throw std::runtime_error( "BucketExistsAsync(): expected bucket to exist"); } @@ -831,10 +834,10 @@ class Tests { minio::s3::RemoveBucketArgs args; args.bucket = bucket_name; auto rm_fut = client_.RemoveBucketAsync(args); - minio::s3::RemoveBucketResponse rm_resp = rm_fut.get(); + auto rm_resp = rm_fut.get(); if (!rm_resp) { throw std::runtime_error("RemoveBucketAsync(): " + - rm_resp.Error().String()); + rm_resp.error().String()); } } } catch (...) { @@ -854,10 +857,10 @@ class Tests { args.bucket = bucket_name_; args.object = object_name; auto put_fut = client_.PutObjectAsync(std::move(args)); - minio::s3::PutObjectResponse put_resp = put_fut.get(); + auto put_resp = put_fut.get(); if (!put_resp) { throw std::runtime_error("PutObjectAsync(): " + - put_resp.Error().String()); + put_resp.error().String()); } } @@ -868,15 +871,15 @@ class Tests { args.bucket = bucket_name_; args.object = object_name; auto stat_fut = client_.StatObjectAsync(std::move(args)); - minio::s3::StatObjectResponse stat_resp = stat_fut.get(); + auto stat_resp = stat_fut.get(); if (!stat_resp) { throw std::runtime_error("StatObjectAsync(): " + - stat_resp.Error().String()); + stat_resp.error().String()); } - if (stat_resp.size != data.length()) { + if (stat_resp->size != data.length()) { throw std::runtime_error("StatObjectAsync(): expected size: " + std::to_string(data.length()) + "; got: " + - std::to_string(stat_resp.size)); + std::to_string(stat_resp->size)); } } @@ -892,10 +895,10 @@ class Tests { return true; }; auto get_fut = client_.GetObjectAsync(std::move(gargs)); - minio::s3::GetObjectResponse get_resp = get_fut.get(); + auto get_resp = get_fut.get(); if (!get_resp) { throw std::runtime_error("GetObjectAsync(): " + - get_resp.Error().String()); + get_resp.error().String()); } if (data != content) { throw std::runtime_error("GetObjectAsync(): expected: " + data + @@ -909,10 +912,10 @@ class Tests { args.bucket = bucket_name_; args.object = object_name; auto rm_fut = client_.RemoveObjectAsync(std::move(args)); - minio::s3::RemoveObjectResponse rm_resp = rm_fut.get(); + auto rm_resp = rm_fut.get(); if (!rm_resp) { throw std::runtime_error("RemoveObjectAsync(): " + - rm_resp.Error().String()); + rm_resp.error().String()); } } } catch (const std::runtime_error&) { @@ -924,10 +927,10 @@ class Tests { // --- async ListBuckets --- { auto fut = client_.ListBucketsAsync(minio::s3::ListBucketsArgs()); - minio::s3::ListBucketsResponse resp = fut.get(); + auto resp = fut.get(); if (!resp) { throw std::runtime_error("ListBucketsAsync(): " + - resp.Error().String()); + resp.error().String()); } } @@ -943,9 +946,9 @@ class Tests { ss, static_cast(data.length()), 0); args.bucket = bucket_name_; args.object = src_object; - minio::s3::PutObjectResponse resp = client_.PutObject(args); + auto resp = client_.PutObject(args); if (!resp) { - throw std::runtime_error("PutObject(): " + resp.Error().String()); + throw std::runtime_error("PutObject(): " + resp.error().String()); } } @@ -957,10 +960,10 @@ class Tests { cargs.object = dst_object; cargs.source = source; auto copy_fut = client_.CopyObjectAsync(std::move(cargs)); - minio::s3::CopyObjectResponse copy_resp = copy_fut.get(); + auto copy_resp = copy_fut.get(); if (!copy_resp) { throw std::runtime_error("CopyObjectAsync(): " + - copy_resp.Error().String()); + copy_resp.error().String()); } RemoveObject(bucket_name_, src_object); @@ -988,10 +991,10 @@ class Tests { args.object = object_name; args.filename = filename; auto up_fut = client_.UploadObjectAsync(std::move(args)); - minio::s3::UploadObjectResponse up_resp = up_fut.get(); + auto up_resp = up_fut.get(); if (!up_resp) { throw std::runtime_error("UploadObjectAsync(): " + - up_resp.Error().String()); + up_resp.error().String()); } std::filesystem::remove(filename); RemoveObject(bucket_name_, object_name); @@ -1012,9 +1015,9 @@ class Tests { 0); args.bucket = bucket_name_; args.object = object_name; - minio::s3::PutObjectResponse resp = client_.PutObject(args); + auto resp = client_.PutObject(args); if (!resp) { - throw std::runtime_error("PutObject(): " + resp.Error().String()); + throw std::runtime_error("PutObject(): " + resp.error().String()); } } @@ -1024,12 +1027,12 @@ class Tests { args.object = object_name; args.method = minio::http::Method::kGet; auto url_fut = client_.GetPresignedObjectUrlAsync(std::move(args)); - minio::s3::GetPresignedObjectUrlResponse url_resp = url_fut.get(); + auto url_resp = url_fut.get(); if (!url_resp) { throw std::runtime_error("GetPresignedObjectUrlAsync(): " + - url_resp.Error().String()); + url_resp.error().String()); } - if (url_resp.url.empty()) { + if (url_resp->url.empty()) { throw std::runtime_error( "GetPresignedObjectUrlAsync(): url is empty"); } @@ -1047,10 +1050,10 @@ class Tests { minio::s3::MakeBucketArgs args; args.bucket = bucket_name; auto fut = client_.MakeBucketAsync(args); - minio::s3::MakeBucketResponse resp = fut.get(); + auto resp = fut.get(); if (!resp) { throw std::runtime_error("MakeBucketAsync(): " + - resp.Error().String()); + resp.error().String()); } } @@ -1062,10 +1065,10 @@ class Tests { minio::s3::Boolean status(true); args.status = status; auto fut = client_.SetBucketVersioningAsync(std::move(args)); - minio::s3::SetBucketVersioningResponse resp = fut.get(); + auto resp = fut.get(); if (!resp) { throw std::runtime_error("SetBucketVersioningAsync(): " + - resp.Error().String()); + resp.error().String()); } } @@ -1074,12 +1077,12 @@ class Tests { minio::s3::GetBucketVersioningArgs args; args.bucket = bucket_name; auto fut = client_.GetBucketVersioningAsync(std::move(args)); - minio::s3::GetBucketVersioningResponse resp = fut.get(); + auto resp = fut.get(); if (!resp) { throw std::runtime_error("GetBucketVersioningAsync(): " + - resp.Error().String()); + resp.error().String()); } - if (!resp.status || !resp.status.Get()) { + if (!resp->status || !resp->status.Get()) { throw std::runtime_error( "GetBucketVersioningAsync(): expected Enabled"); } @@ -1089,10 +1092,10 @@ class Tests { minio::s3::RemoveBucketArgs args; args.bucket = bucket_name; auto fut = client_.RemoveBucketAsync(args); - minio::s3::RemoveBucketResponse resp = fut.get(); + auto resp = fut.get(); if (!resp) { throw std::runtime_error("RemoveBucketAsync(): " + - resp.Error().String()); + resp.error().String()); } } } catch (const std::runtime_error&) { @@ -1113,9 +1116,9 @@ class Tests { 0); args.bucket = bucket_name_; args.object = object_name; - minio::s3::PutObjectResponse resp = client_.PutObject(args); + auto resp = client_.PutObject(args); if (!resp) { - throw std::runtime_error("PutObject(): " + resp.Error().String()); + throw std::runtime_error("PutObject(): " + resp.error().String()); } } @@ -1127,10 +1130,10 @@ class Tests { args.object = object_name; args.tags = {{"key1", "value1"}, {"key2", "value2"}}; auto fut = client_.SetObjectTagsAsync(std::move(args)); - minio::s3::SetObjectTagsResponse resp = fut.get(); + auto resp = fut.get(); if (!resp) { throw std::runtime_error("SetObjectTagsAsync(): " + - resp.Error().String()); + resp.error().String()); } } @@ -1140,13 +1143,13 @@ class Tests { args.bucket = bucket_name_; args.object = object_name; auto fut = client_.GetObjectTagsAsync(std::move(args)); - minio::s3::GetObjectTagsResponse resp = fut.get(); + auto resp = fut.get(); if (!resp) { throw std::runtime_error("GetObjectTagsAsync(): " + - resp.Error().String()); + resp.error().String()); } - if (resp.tags.size() != 2 || resp.tags["key1"] != "value1" || - resp.tags["key2"] != "value2") { + if (resp->tags.size() != 2 || resp->tags["key1"] != "value1" || + resp->tags["key2"] != "value2") { throw std::runtime_error("GetObjectTagsAsync(): tag mismatch"); } } @@ -1157,10 +1160,10 @@ class Tests { args.bucket = bucket_name_; args.object = object_name; auto fut = client_.DeleteObjectTagsAsync(std::move(args)); - minio::s3::DeleteObjectTagsResponse resp = fut.get(); + auto resp = fut.get(); if (!resp) { throw std::runtime_error("DeleteObjectTagsAsync(): " + - resp.Error().String()); + resp.error().String()); } } @@ -1178,10 +1181,10 @@ class Tests { minio::s3::MakeBucketArgs args; args.bucket = bucket_name; auto fut = client_.MakeBucketAsync(args); - minio::s3::MakeBucketResponse resp = fut.get(); + auto resp = fut.get(); if (!resp) { throw std::runtime_error("MakeBucketAsync(): " + - resp.Error().String()); + resp.error().String()); } } @@ -1192,10 +1195,10 @@ class Tests { args.bucket = bucket_name; args.tags = {{"department", "engineering"}}; auto fut = client_.SetBucketTagsAsync(std::move(args)); - minio::s3::SetBucketTagsResponse resp = fut.get(); + auto resp = fut.get(); if (!resp) { throw std::runtime_error("SetBucketTagsAsync(): " + - resp.Error().String()); + resp.error().String()); } } @@ -1204,13 +1207,13 @@ class Tests { minio::s3::GetBucketTagsArgs args; args.bucket = bucket_name; auto fut = client_.GetBucketTagsAsync(std::move(args)); - minio::s3::GetBucketTagsResponse resp = fut.get(); + auto resp = fut.get(); if (!resp) { throw std::runtime_error("GetBucketTagsAsync(): " + - resp.Error().String()); + resp.error().String()); } - if (resp.tags.size() != 1 || - resp.tags["department"] != "engineering") { + if (resp->tags.size() != 1 || + resp->tags["department"] != "engineering") { throw std::runtime_error("GetBucketTagsAsync(): tag mismatch"); } } @@ -1220,10 +1223,10 @@ class Tests { minio::s3::DeleteBucketTagsArgs args; args.bucket = bucket_name; auto fut = client_.DeleteBucketTagsAsync(std::move(args)); - minio::s3::DeleteBucketTagsResponse resp = fut.get(); + auto resp = fut.get(); if (!resp) { throw std::runtime_error("DeleteBucketTagsAsync(): " + - resp.Error().String()); + resp.error().String()); } } @@ -1231,10 +1234,10 @@ class Tests { minio::s3::RemoveBucketArgs args; args.bucket = bucket_name; auto fut = client_.RemoveBucketAsync(args); - minio::s3::RemoveBucketResponse resp = fut.get(); + auto resp = fut.get(); if (!resp) { throw std::runtime_error("RemoveBucketAsync(): " + - resp.Error().String()); + resp.error().String()); } } } catch (const std::runtime_error&) { @@ -1248,10 +1251,10 @@ class Tests { // --- async ListBuckets (no-arg overload) --- { auto fut = client_.ListBucketsAsync(); - minio::s3::ListBucketsResponse resp = fut.get(); + auto resp = fut.get(); if (!resp) { throw std::runtime_error("ListBucketsAsync() (no-arg): " + - resp.Error().String()); + resp.error().String()); } } @@ -1261,12 +1264,12 @@ class Tests { args.bucket = bucket_name_; args.object = "__nonexistent_object_async_test__"; auto fut = client_.StatObjectAsync(std::move(args)); - minio::s3::StatObjectResponse resp = fut.get(); + auto resp = fut.get(); if (resp) { throw std::runtime_error( "StatObjectAsync() on nonexistent object: expected failure"); } - if (resp.Error().String().empty()) { + if (resp.error().String().empty()) { throw std::runtime_error( "StatObjectAsync() on nonexistent object: expected error message"); } @@ -1316,7 +1319,15 @@ class Tests { auto fe1 = client_.BucketExistsAsync(std::move(be1)); auto fe2 = client_.BucketExistsAsync(std::move(be2)); auto fe3 = client_.BucketExistsAsync(std::move(be3)); - if (!fe1.get().exist || !fe2.get().exist || !fe3.get().exist) { + auto fe1_resp = fe1.get(); + auto fe2_resp = fe2.get(); + auto fe3_resp = fe3.get(); + if (!fe1_resp || !fe2_resp || !fe3_resp) { + cleanup(b1, b2, b3); + throw std::runtime_error( + "concurrent BucketExistsAsync(): one failed"); + } + if (!fe1_resp->exist || !fe2_resp->exist || !fe3_resp->exist) { cleanup(b1, b2, b3); throw std::runtime_error( "concurrent BucketExistsAsync(): expected true"); @@ -1341,20 +1352,20 @@ class Tests { } } - std::future enc_fut; + std::future> enc_fut; { // SseConfig lives only in this scope; async must own a copy. - minio::s3::SseConfig sse_config = minio::s3::SseConfig::S3(); + auto sse_config = minio::s3::SseConfig::S3(); minio::s3::SetBucketEncryptionArgs enc_args(sse_config); enc_args.bucket = bucket_name; enc_fut = client_.SetBucketEncryptionAsync(std::move(enc_args)); // sse_config and enc_args go out of scope here. } - minio::s3::SetBucketEncryptionResponse enc_resp = enc_fut.get(); + auto enc_resp = enc_fut.get(); if (!enc_resp) { std::cout << " SetBucketEncryptionAsync skipped: " - << enc_resp.Error().String() << std::endl; + << enc_resp.error().String() << std::endl; } { @@ -1376,7 +1387,7 @@ class Tests { } } - std::future lc_fut; + std::future> lc_fut; { minio::s3::LifecycleConfig lc_config; minio::s3::SetBucketLifecycleArgs lc_args(lc_config); @@ -1385,10 +1396,10 @@ class Tests { // lc_config and lc_args go out of scope here. } - minio::s3::SetBucketLifecycleResponse lc_resp = lc_fut.get(); + auto lc_resp = lc_fut.get(); if (!lc_resp) { std::cout << " SetBucketLifecycleAsync skipped: " - << lc_resp.Error().String() << std::endl; + << lc_resp.error().String() << std::endl; } { @@ -1410,7 +1421,7 @@ class Tests { } } - std::future notif_fut; + std::future> notif_fut; { minio::s3::NotificationConfig notif_config; minio::s3::SetBucketNotificationArgs notif_args(notif_config); @@ -1419,10 +1430,10 @@ class Tests { // notif_config and notif_args go out of scope here. } - minio::s3::SetBucketNotificationResponse notif_resp = notif_fut.get(); + auto notif_resp = notif_fut.get(); if (!notif_resp) { std::cout << " SetBucketNotificationAsync skipped: " - << notif_resp.Error().String() << std::endl; + << notif_resp.error().String() << std::endl; } { @@ -1444,7 +1455,7 @@ class Tests { } } - std::future repl_fut; + std::future> repl_fut; { minio::s3::ReplicationConfig repl_config; minio::s3::SetBucketReplicationArgs repl_args(repl_config); @@ -1453,10 +1464,10 @@ class Tests { // repl_config and repl_args go out of scope here. } - minio::s3::SetBucketReplicationResponse repl_resp = repl_fut.get(); + auto repl_resp = repl_fut.get(); if (!repl_resp) { std::cout << " SetBucketReplicationAsync skipped: " - << repl_resp.Error().String() << std::endl; + << repl_resp.error().String() << std::endl; } { @@ -1484,7 +1495,7 @@ class Tests { } } - std::future sel_fut; + std::future> sel_fut; std::string records; { std::string expression = "select * from S3Object"; @@ -1494,7 +1505,7 @@ class Tests { csv_input.file_header_info = std::make_shared(file_header_info); minio::s3::CsvOutputSerialization csv_output; - minio::s3::QuoteFields quote_fields = minio::s3::QuoteFields::kAsNeeded; + auto quote_fields = minio::s3::QuoteFields::kAsNeeded; csv_output.quote_fields = std::make_shared(quote_fields); @@ -1513,14 +1524,15 @@ class Tests { // csv_input, csv_output, request, etc. go out of scope here. } - minio::s3::SelectObjectContentResponse sel_resp = sel_fut.get(); - if (!sel_resp && sel_resp.code == "MethodNotAllowed") { + auto sel_resp = sel_fut.get(); + if (!sel_resp && sel_resp.error().String().find("MethodNotAllowed") != + std::string::npos) { std::cout << " SelectObjectContentAsync skipped: server does not " "implement S3 Select" << std::endl; } else if (!sel_resp) { throw std::runtime_error("SelectObjectContentAsync(): " + - sel_resp.Error().String()); + sel_resp.error().String()); } RemoveObject(bucket_name_, object_name); }