blob: 75f0b6cfd5ba1e02792df6e766c3c493acc750df [file] [log] [blame]
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef LIB_ZXIO_VECTOR_H_
#define LIB_ZXIO_VECTOR_H_
#include <zircon/types.h>
// Calls the callback |fn| for every buffer in |vector| or until the callback
// returns |ZX_ERR_STOP|.
//
// **NOTE**: This method will return an error even if *some* progress has been
// made which is typically not what you want and does not match some POSIX APIs
// (generally on stream-like objects like Files, TCP sockets) which will return
// success for short reads and writes. If this method is used by such APIs, you
// most likely want to use |zxio_stream_do_vector| below, which will return
// partial success.
template <typename F>
zx_status_t zxio_do_vector(const zx_iovec_t* vector, size_t vector_count, size_t* out_actual,
F fn) {
size_t total = 0;
for (size_t i = 0; i < vector_count; ++i) {
size_t actual = 0;
zx_status_t status = fn(vector[i].buffer, vector[i].capacity, total, &actual);
switch (status) {
case ZX_OK:
case ZX_ERR_NEXT:
total += actual;
if (actual == vector[i].capacity) {
continue;
}
// Short read.
break;
case ZX_ERR_STOP:
total += actual;
break;
default:
return status;
}
break;
}
*out_actual = total;
return ZX_OK;
}
// This method is like |zxio_do_vector| except it implements stream semantics.
// That is, this method will swallow the error returned by |fn|, stop iterating
// the buffers and return |ZX_OK| as long as a previous call to |fn| successfully
// performed some I/O on at least one byte. If |fn| returns an error before any
// I/O was performed (no bytes were read/written), then that error is returned
// to the caller.
template <typename F>
zx_status_t zxio_stream_do_vector(const zx_iovec_t* vector, size_t vector_count, size_t* out_actual,
F fn) {
return zxio_do_vector(
vector, vector_count, out_actual,
[&](void* buffer, size_t capacity, size_t total_so_far, size_t* out_actual) {
zx_status_t status = fn(buffer, capacity, out_actual);
if (status != ZX_OK) {
if (total_so_far == 0) {
return status;
}
return ZX_ERR_STOP;
}
return ZX_ERR_NEXT;
});
}
#endif // LIB_ZXIO_VECTOR_H_