aboutsummaryrefslogtreecommitdiff
path: root/lib/std/io/change_detection_stream.zig
blob: 57ef8a82bd64fc3cf72227ea5f4216a238addf25 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
// SPDX-License-Identifier: MIT
// Copyright (c) 2015-2021 Zig Contributors
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
// The MIT license requires this copyright notice to be included in all copies
// and substantial portions of the software.

const std = @import("../std.zig");
const io = std.io;
const mem = std.mem;
const assert = std.debug.assert;

/// Used to detect if the data written to a stream differs from a source buffer
pub fn ChangeDetectionStream(comptime WriterType: type) type {
    return struct {
        const Self = @This();
        pub const Error = WriterType.Error;
        pub const Writer = io.Writer(*Self, Error, write);

        anything_changed: bool,
        underlying_writer: WriterType,
        source_index: usize,
        source: []const u8,

        pub fn writer(self: *Self) Writer {
            return .{ .context = self };
        }

        fn write(self: *Self, bytes: []const u8) Error!usize {
            if (!self.anything_changed) {
                const end = self.source_index + bytes.len;
                if (end > self.source.len) {
                    self.anything_changed = true;
                } else {
                    const src_slice = self.source[self.source_index..end];
                    self.source_index += bytes.len;
                    if (!mem.eql(u8, bytes, src_slice)) {
                        self.anything_changed = true;
                    }
                }
            }

            return self.underlying_writer.write(bytes);
        }

        pub fn changeDetected(self: *Self) bool {
            return self.anything_changed or (self.source_index != self.source.len);
        }
    };
}

pub fn changeDetectionStream(
    source: []const u8,
    underlying_writer: anytype,
) ChangeDetectionStream(@TypeOf(underlying_writer)) {
    return ChangeDetectionStream(@TypeOf(underlying_writer)){
        .anything_changed = false,
        .underlying_writer = underlying_writer,
        .source_index = 0,
        .source = source,
    };
}