diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 06ea556..5f15df4 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -12,19 +12,13 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - name: Checkout + uses: actions/checkout@v4 - - name: Download zig - run: wget https://ziglang.org/builds/zig-linux-x86_64-0.15.0-dev.75+03123916e.tar.xz - - - name: Extract - run: tar -xf zig-linux-x86_64-0.15.0-dev.75+03123916e.tar.xz - - - name: Alias - run: alias zig=$PWD/zig-linux-x86_64-0.15.0-dev.75+03123916e/zig - - - name: Version - run: $PWD/zig-linux-x86_64-0.15.0-dev.75+03123916e/zig version + - name: Setup Zig + uses: mlugg/setup-zig@v2 + with: + version: 0.15.1 - name: Test - run: $PWD/zig-linux-x86_64-0.15.0-dev.75+03123916e/zig build test + run: zig build test diff --git a/build.zig b/build.zig index e44cbf6..8861115 100644 --- a/build.zig +++ b/build.zig @@ -4,14 +4,23 @@ pub fn build(b: *std.Build) void { const target = b.standardTargetOptions(.{}); const optimize = b.standardOptimizeOption(.{}); - _ = b.addModule("string", .{ .root_source_file = b.path("zig-string.zig") }); + _ = b.addModule("string", .{ + .root_source_file = b.path("zig-string.zig"), + .target = target, + .optimize = optimize, + }); - var main_tests = b.addTest(.{ + const test_mod = b.addModule("string-tests", .{ .root_source_file = b.path("zig-string-tests.zig"), .target = target, .optimize = optimize, }); + const main_tests = b.addTest(.{ + .root_module = test_mod, + }); + + const run_main_tests = b.addRunArtifact(main_tests); const test_step = b.step("test", "Run library tests"); - test_step.dependOn(&main_tests.step); + test_step.dependOn(&run_main_tests.step); } diff --git a/build.zig.zon b/build.zig.zon index f8ed803..4725bc1 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -1,7 +1,7 @@ .{ .name = .zig_string, .version = "0.10.0", - .minimum_zig_version = "0.14.0", + .minimum_zig_version = "0.15.1", .fingerprint = 0xd2ee692e5a4bdae9, .paths = .{""}, } diff --git a/zig-string-tests.zig b/zig-string-tests.zig index 7666529..d12b43e 100644 --- a/zig-string-tests.zig +++ b/zig-string-tests.zig @@ -184,9 +184,11 @@ test "String Tests" { try expectEqual(myStr.size, 0); // writer - const writer = myStr.writer(); - const length = try writer.write("This is a Test!"); + var writer = myStr.writer(&.{}); + const w = &writer.interface; + const length = try w.write("This is a Test!"); try expectEqual(length, 15); + try w.flush(); // owned const mySlice = try myStr.toOwned(); @@ -300,4 +302,4 @@ test "includes Tests" { try expect(myString.includesLiteral("") == false); try expect(myString.includesString(needle) == false); -} \ No newline at end of file +} diff --git a/zig-string.zig b/zig-string.zig index 5912276..f161c4e 100644 --- a/zig-string.zig +++ b/zig-string.zig @@ -359,15 +359,16 @@ pub const String = struct { /// Splits the String into slices, based on a delimiter. pub fn splitAll(self: *const String, delimiters: []const u8) ![][]const u8 { - var splitArr = std.ArrayList([]const u8).init(std.heap.page_allocator); - defer splitArr.deinit(); + const allocator = std.heap.page_allocator; + var splitArr: std.ArrayList([]const u8) = .empty; + errdefer splitArr.deinit(allocator); var i: usize = 0; while (self.split(delimiters, i)) |slice| : (i += 1) { - try splitArr.append(slice); + try splitArr.append(allocator, slice); } - return try splitArr.toOwnedSlice(); + return try splitArr.toOwnedSlice(allocator); } /// Splits the String into a new string, based on delimiters and an index @@ -385,22 +386,20 @@ pub const String = struct { /// Splits the String into a slice of new Strings, based on delimiters. /// The user of this function is in charge of the memory of the new Strings. pub fn splitAllToStrings(self: *const String, delimiters: []const u8) ![]String { - var splitArr = std.ArrayList(String).init(std.heap.page_allocator); - defer splitArr.deinit(); + const allocator = std.heap.page_allocator; + var splitArr: std.ArrayList(String) = .empty; + errdefer splitArr.deinit(allocator); var i: usize = 0; while (try self.splitToString(delimiters, i)) |splitStr| : (i += 1) { - try splitArr.append(splitStr); + try splitArr.append(allocator, splitStr); } - return try splitArr.toOwnedSlice(); + return try splitArr.toOwnedSlice(allocator); } /// Splits the String into a slice of Strings by new line (\r\n or \n). pub fn lines(self: *String) ![]String { - var lineArr = std.ArrayList(String).init(std.heap.page_allocator); - defer lineArr.deinit(); - var selfClone = try self.clone(); defer selfClone.deinit(); @@ -486,45 +485,66 @@ pub const String = struct { } // Writer functionality for the String. - pub usingnamespace struct { - pub const Writer = std.io.Writer(*String, Error, appendWrite); - - pub fn writer(self: *String) Writer { - return .{ .context = self }; - } - - fn appendWrite(self: *String, m: []const u8) !usize { - try self.concat(m); - return m.len; + // pub const Writer = std.io.Writer(*String, Error, appendWrite); + pub const Writer = struct { + string: *String, + interface: std.Io.Writer, + err: ?Error = null, + + fn drain(w: *std.Io.Writer, data: []const []const u8, splat: usize) std.Io.Writer.Error!usize { + _ = splat; + const a: *@This() = @alignCast(@fieldParentPtr("interface", w)); + const buffered = w.buffered(); + if (buffered.len != 0) return w.consume(a.string.appendWrite(buffered) catch |err| { + a.err = err; + return error.WriteFailed; + }); + return a.string.appendWrite(data[0]) catch |err| { + a.err = err; + return error.WriteFailed; + }; } }; - // Iterator support - pub usingnamespace struct { - pub const StringIterator = struct { - string: *const String, - index: usize, - - pub fn next(it: *StringIterator) ?[]const u8 { - if (it.string.buffer) |buffer| { - if (it.index == it.string.size) return null; - const i = it.index; - it.index += String.getUTF8Size(buffer[i]); - return buffer[i..it.index]; - } else { - return null; - } - } + pub fn writer(self: *String, buffer: []u8) Writer { + return .{ + .string = self, + .interface = .{ + .buffer = buffer, + .vtable = &.{ .drain = Writer.drain }, + }, }; + } - pub fn iterator(self: *const String) StringIterator { - return StringIterator{ - .string = self, - .index = 0, - }; + fn appendWrite(self: *String, m: []const u8) !usize { + try self.concat(m); + return m.len; + } + + // Iterator support + pub const StringIterator = struct { + string: *const String, + index: usize, + + pub fn next(it: *StringIterator) ?[]const u8 { + if (it.string.buffer) |buffer| { + if (it.index == it.string.size) return null; + const i = it.index; + it.index += String.getUTF8Size(buffer[i]); + return buffer[i..it.index]; + } else { + return null; + } } }; + pub fn iterator(self: *const String) StringIterator { + return StringIterator{ + .string = self, + .index = 0, + }; + } + /// Returns whether or not a character is whitelisted fn inWhitelist(char: u8, whitelist: []const u8) bool { var i: usize = 0; @@ -609,7 +629,6 @@ pub const String = struct { /// Checks if the needle String is within the source String pub fn includesString(self: *String, needle: String) bool { - if (self.size == 0 or needle.size == 0) return false; if (self.buffer) |buffer| { @@ -627,7 +646,6 @@ pub const String = struct { /// Checks if the needle literal is within the source String pub fn includesLiteral(self: *String, needle: []const u8) bool { - if (self.size == 0 or needle.len == 0) return false; if (self.buffer) |buffer| {