aboutsummaryrefslogtreecommitdiffstats
path: root/src/block_dumper.h
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2023-02-27 21:19:15 -0500
committerDavid Robillard <d@drobilla.net>2023-12-02 18:49:08 -0500
commit2d5e6aa234faeb406911ed44f56038dc73f8ff8e (patch)
treeeae09c3e3b0acc7a7ac1f1f45d0ad637d939f145 /src/block_dumper.h
parentba897eee8f9a55ab31e338a036fe924bc90be5ef (diff)
downloadserd-2d5e6aa234faeb406911ed44f56038dc73f8ff8e.tar.gz
serd-2d5e6aa234faeb406911ed44f56038dc73f8ff8e.tar.bz2
serd-2d5e6aa234faeb406911ed44f56038dc73f8ff8e.zip
[WIP] Simplify block writing interface and improve error handling
Diffstat (limited to 'src/block_dumper.h')
-rw-r--r--src/block_dumper.h55
1 files changed, 34 insertions, 21 deletions
diff --git a/src/block_dumper.h b/src/block_dumper.h
index 038f0a82..9820ed03 100644
--- a/src/block_dumper.h
+++ b/src/block_dumper.h
@@ -7,15 +7,16 @@
#include "serd/output_stream.h"
#include "serd/status.h"
#include "serd/world.h"
+#include "serd/write_result.h"
#include "zix/allocator.h"
#include "zix/attributes.h"
#include <stddef.h>
#include <string.h>
+/// The partially inlinable sink interface used by the writer
typedef struct {
- ZixAllocator* ZIX_NONNULL allocator; ///< Buffer allocator
-
+ ZixAllocator* ZIX_NONNULL allocator; ///< Buffer allocator
SerdOutputStream* ZIX_ALLOCATED out; ///< Output stream to write to
char* ZIX_ALLOCATED buf; ///< Local buffer if needed
size_t size; ///< Bytes pending for this block
@@ -34,6 +35,12 @@ serd_block_dumper_open(const SerdWorld* ZIX_NONNULL world,
SerdOutputStream* ZIX_NONNULL output,
size_t block_size);
+/**
+ Flush any pending writes.
+
+ This is typically used before closing to ensure that all of the writes have
+ actually been written to disk.
+*/
SerdStatus
serd_block_dumper_flush(SerdBlockDumper* ZIX_NONNULL dumper);
@@ -46,37 +53,43 @@ serd_block_dumper_close(SerdBlockDumper* ZIX_NONNULL dumper);
This works like any other SerdWriteFunc, but will append to an internal
buffer and only actually write to the output when a whole block is ready.
*/
-static inline size_t
-serd_block_dumper_write(const void* ZIX_NONNULL buf,
- const size_t size,
- const size_t nmemb,
- SerdBlockDumper* ZIX_NONNULL const dumper)
+static inline SerdWriteResult
+serd_block_dumper_write(SerdBlockDumper* ZIX_NONNULL const dumper,
+ const void* ZIX_NONNULL buf,
+ const size_t size)
{
- if (dumper->block_size == 1) {
- return dumper->out->write(buf, size, nmemb, dumper->out->stream);
+ SerdWriteResult result = {SERD_SUCCESS, 0U};
+ const size_t block_size = dumper->block_size;
+ const SerdOutputStream* const out = dumper->out;
+
+ if (block_size == 1) {
+ result.count = out->write(buf, 1U, size, out->stream);
+ result.status = result.count == size ? SERD_SUCCESS : SERD_BAD_WRITE;
+ return result;
}
- size_t len = size * nmemb;
- const size_t orig_len = len;
- while (len) {
- const size_t space = dumper->block_size - dumper->size;
- const size_t n = space < len ? space : len;
+ while (result.count < size) {
+ const size_t unwritten = size - result.count;
+ const size_t space = block_size - dumper->size;
+ const size_t n = space < unwritten ? space : unwritten;
// Write as much as possible into the remaining buffer space
- memcpy(dumper->buf + dumper->size, buf, n);
+ memcpy(dumper->buf + dumper->size, (const char*)buf + result.count, n);
dumper->size += n;
- buf = (const char*)buf + n;
- len -= n;
+ result.count += n;
// Flush page if buffer is full
- if (dumper->size == dumper->block_size) {
- dumper->out->write(
- dumper->buf, 1, dumper->block_size, dumper->out->stream);
+ if (dumper->size == block_size) {
+ if (out->write(dumper->buf, 1, block_size, out->stream) != block_size) {
+ result.status = SERD_BAD_WRITE;
+ return result;
+ }
+
dumper->size = 0;
}
}
- return orig_len;
+ return result;
}
#endif // SERD_SRC_DUMPER_H