std.Io.Reader and std.Io.Writer
interfaces. Wrap an existing reader or writer and the conversion happens
transparently as data streams through.
- Zig 98.4%
- Nix 1.6%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
`zig build bench` streams 8 MiB input profiles (typical lines, dense 2-char lines, no endings, lone CRs) through each adapter into a discarding writer and reports best-of-5 MB/s against a chunked memcpy baseline. Pass-through runs at memcpy speed; converting workloads run at 2.4-3.8 GB/s on typical text. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016WV3MLFkp4cZoKgu4HCyD7 |
||
| LICENSES | ||
| src | ||
| .gitignore | ||
| build.zig | ||
| build.zig.zon | ||
| flake.lock | ||
| flake.nix | ||
| README.md | ||
| REUSE.toml | ||
zig-crlf
Line-ending conversion adapters for Zig's std.Io.Reader and std.Io.Writer
interfaces. Wrap an existing reader or writer and the conversion happens
transparently as data streams through.
Requires Zig 0.16.0.
Semantics
CrlfToLfReader/CrlfToLfWriterconvert CRLF (\r\n) to LF (\n). A CR that is not followed by LF is passed through unchanged.LfToCrlfReader/LfToCrlfWriterconvert LF (\n) to CRLF (\r\n). An LF that is already preceded by CR is passed through unchanged, so existing CRLF sequences are not doubled.
Because lone CRs pass through and existing CRLFs are never doubled, LF → CRLF → LF round trips losslessly.
Usage
Fetch and add the dependency:
zig fetch --save <url>
const mod = b.addModule("my_module", .{ ... });
mod.addImport("zig_crlf", b.dependency("zig_crlf", .{}).module("zig_crlf"));
Converting while reading:
const zig_crlf = @import("zig_crlf");
var buffer: [4096]u8 = undefined;
var converted: zig_crlf.CrlfToLfReader = .init(some_reader, &buffer);
// Read LF-terminated data from converted.interface, e.g.:
const line = try converted.interface.takeDelimiterExclusive('\n');
Converting while writing:
var buffer: [4096]u8 = undefined;
var converted: zig_crlf.LfToCrlfWriter = .init(some_writer, &buffer);
try converted.writer.print("hello\n", .{}); // writes "hello\r\n" downstream
try converted.writer.flush();
CrlfToLfWriter is the one special case: a trailing CR cannot be forwarded
until the byte after it is seen, so call finish() instead of flush() once
all data has been written.
The underlying reader passed to CrlfToLfReader must have a buffer capacity
of at least 2 bytes so a CRLF pair split across two fills can be reassembled.
CLI
The package also builds a small demo filter:
zig build
zig-out/bin/zig_crlf --to-lf < dos.txt > unix.txt
zig-out/bin/zig_crlf --to-crlf < unix.txt > dos.txt
Development
zig build test # run unit tests (fuzz bodies run once as smoke tests)
zig build test --fuzz # fuzz the adapters against reference implementations
zig build docs # generate API documentation into zig-out/docs
zig build bench # run throughput benchmarks (ReleaseFast)
Note that src/test_runner.zig is a vendored copy of Zig's default test
runner patched for a zig 0.16.0 bug that breaks compilation in fuzz mode, and
tests are built with the LLVM backend because the self-hosted backend emits no
fuzz coverage (ziglang/zig#30655).
License
MIT. This project is REUSE compliant.