docs: private Iterable<Result<Part>> listObjectParts(final String bucketName, final String objectName,
                                                   final String uploadId) {
      return new Iterable<Result<Part>>() {
        @Override
        public Iterator<Result<Part>> iterator() {
          return new Iterator<Result<Part>>() {
            private int nextPartNumberMarker;
            private ListPartsResult listPartsResult;
            private Result<Part> error;
            private Iterator<Part> partIterator;
            private boolean completed = false;
  
            private synchronized void populate() {
              this.listPartsResult = null;
              this.partIterator = null;
  
              try {
                this.listPartsResult = listObjectParts(bucketName, objectName, uploadId, nextPartNumberMarker);
              } catch (InvalidBucketNameException | NoSuchAlgorithmException | InsufficientDataException | IOException
                       | InvalidKeyException | NoResponseException | XmlPullParserException | ErrorResponseException
                       | InternalException e) {
                this.error = new Result<>(null, e);
              } finally {
                if (this.listPartsResult != null) {
                  this.partIterator = this.listPartsResult.partList().iterator();
                } else {
                  this.partIterator = new LinkedList<Part>().iterator();
                }
              }
            }
  
            @Override
            public boolean hasNext() {
              if (this.completed) {
                return false;
              }
  
              if (this.error == null && this.partIterator == null) {
                populate();
              }
  
              if (this.error == null && !this.partIterator.hasNext() && this.listPartsResult.isTruncated()) {
                this.nextPartNumberMarker = this.listPartsResult.nextPartNumberMarker();
                populate();
              }
  
              if (this.error != null) {
                return true;
              }
  
              if (this.partIterator.hasNext()) {
                return true;
              }
  
              this.completed = true;
              return false;
            }
  
            @Override
            public Result<Part> next() {
              if (this.completed) {
                throw new NoSuchElementException();
              }
  
              if (this.error == null && this.partIterator == null) {
                populate();
              }
  
              if (this.error == null && !this.partIterator.hasNext() && this.listPartsResult.isTruncated()) {
                this.nextPartNumberMarker = this.listPartsResult.nextPartNumberMarker();
                populate();
              }
  
              if (this.error != null) {
                this.completed = true;
                return this.error;
              }
  
              if (this.partIterator.hasNext()) {
                return new Result<>(this.partIterator.next(), null);
              }
  
              this.completed = true;
              throw new NoSuchElementException();
            }
  
            @Override
            public void remove() {
              throw new UnsupportedOperationException();
            }
          };
        }
      };
    }