diff --git a/build.zig b/build.zig index 91ded83..45523bf 100644 --- a/build.zig +++ b/build.zig @@ -1,6 +1,8 @@ const builtin = @import("builtin"); const std = @import("std"); +const zig_atleast_16 = @import("builtin").zig_version.order(.{ .major = 0, .minor = 16, .patch = 0 }) != .lt; + /// Create the xtt (x11 true type) module with a custom TrueType module. pub fn createXtt(b: *std.Build, zigx_dep: *std.Build.Dependency, TrueType: *std.Build.Module) *std.Build.Module { return b.createModule(.{ @@ -38,10 +40,17 @@ pub fn build(b: *std.Build) void { const target = b.standardTargetOptions(.{}); const optimize = b.standardOptimizeOption(.{}); + const zigversion_mod = b.createModule(.{ + .root_source_file = if (zig_atleast_16) b.path("zigversion/atleast16.zig") else b.path("zigversion/before16.zig"), + }); + // In almost all cases, Zig programs should only use this module, not the // library defined below, that's for C programs. const x_mod = b.addModule("x11", .{ .root_source_file = b.path("src/x.zig"), + .imports = &.{ + .{ .name = "zigversion", .module = zigversion_mod }, + }, }); const true_type_mod = b.dependency("TrueType", .{}).module("TrueType"); @@ -178,6 +187,9 @@ pub fn build(b: *std.Build) void { const x_mod_with_target = b.createModule(.{ .root_source_file = b.path("src/x.zig"), .target = target, + .imports = &.{ + .{ .name = "zigversion", .module = zigversion_mod }, + }, }); const unit_tests = b.addTest(.{ .root_module = x_mod_with_target, diff --git a/src/x.zig b/src/x.zig index 2284962..c7a1806 100644 --- a/src/x.zig +++ b/src/x.zig @@ -25,6 +25,7 @@ // ...todo... // +const zigversion = @import("zigversion"); const std = @import("std"); const stdext = @import("stdext.zig"); const testing = std.testing; @@ -62,8 +63,8 @@ pub const record = @compileError("todo"); pub const BoundedArray = @import("bounded_array.zig").BoundedArray; pub const charset = @import("charset.zig"); pub const Charset = charset.Charset; -pub const Slice = @import("x/slice.zig").Slice; -pub const SliceWithMaxLen = @import("x/slice.zig").SliceWithMaxLen; +pub const Slice = zigversion.Slice; +pub const SliceWithMaxLen = zigversion.SliceWithMaxLen; pub const keymap = @import("keymap.zig"); pub const log = std.log.scoped(.x11); @@ -1086,46 +1087,7 @@ const FmtRead = struct { } }; -pub fn ArrayPointer(comptime T: type) type { - const err = "ArrayPointer not implemented for " ++ @typeName(T); - switch (@typeInfo(T)) { - .pointer => |info| { - switch (info.size) { - .one => { - switch (@typeInfo(info.child)) { - .Array => |array_info| { - return @Type(std.builtin.Type{ .pointer = .{ - .size = .Many, - .is_const = true, - .is_volatile = false, - .alignment = @alignOf(array_info.child), - .address_space = info.address_space, - .child = array_info.child, - .is_allowzero = false, - .sentinel = array_info.sentinel, - } }); - }, - else => @compileError("here"), - } - }, - .slice => { - return @Type(std.builtin.Type{ .pointer = .{ - .size = .many, - .is_const = info.is_const, - .is_volatile = info.is_volatile, - .alignment = info.alignment, - .address_space = info.address_space, - .child = info.child, - .is_allowzero = info.is_allowzero, - .sentinel_ptr = info.sentinel_ptr, - } }); - }, - else => @compileError(err), - } - }, - else => @compileError(err), - } -} +pub const ArrayPointer = zigversion.ArrayPointer; pub fn slice(comptime LenType: type, s: anytype) Slice(LenType, ArrayPointer(@TypeOf(s))) { switch (@typeInfo(@TypeOf(s))) { @@ -3929,19 +3891,7 @@ pub const VisualType = extern struct { unused: u32, }; -pub fn NonExhaustive(comptime T: type) type { - const info = switch (@typeInfo(T)) { - .@"enum" => |info| info, - else => |info| @compileError("expected an Enum type but got a(n) " ++ @tagName(info)), - }; - std.debug.assert(info.is_exhaustive); - return @Type(std.builtin.Type{ .@"enum" = .{ - .tag_type = info.tag_type, - .fields = info.fields, - .decls = &.{}, - .is_exhaustive = false, - } }); -} +pub const NonExhaustive = zigversion.NonExhaustive; pub const ImageByteOrder = enum(u8) { lsb_first = 0, msb_first = 1, diff --git a/zigversion/atleast16.zig b/zigversion/atleast16.zig new file mode 100644 index 0000000..9bff799 --- /dev/null +++ b/zigversion/atleast16.zig @@ -0,0 +1,54 @@ +pub const Slice = @import("sliceatleast16.zig").Slice; +pub const SliceWithMaxLen = @import("sliceatleast16.zig").SliceWithMaxLen; + +pub fn NonExhaustive(comptime T: type) type { + const info = switch (@typeInfo(T)) { + .@"enum" => |info| info, + else => |info| @compileError("expected an Enum type but got a(n) " ++ @tagName(info)), + }; + std.debug.assert(info.is_exhaustive); + var names: [info.fields.len][]const u8 = undefined; + var values: [info.fields.len]info.tag_type = undefined; + for (&names, &values, info.fields) |*name, *value, field| { + name.* = field.name; + value.* = field.value; + } + return @Enum(info.tag_type, .nonexhaustive, &names, &values); +} + +pub fn ArrayPointer(comptime T: type) type { + const err = "ArrayPointer not implemented for " ++ @typeName(T); + return switch (@typeInfo(T)) { + .pointer => |info| { + switch (info.size) { + .one => switch (@typeInfo(info.child)) { + .Array => |array_info| @Pointer( + .many, + .{ + .@"const" = true, + }, + array_info.child, + array_info.sentinel, + ), + else => @compileError(err), + }, + .slice => @Pointer( + .many, + .{ + .@"const" = info.is_const, + .@"volatile" = info.is_volatile, + .@"align" = info.alignment, + .@"addrspace" = info.address_space, + .@"allowzero" = info.is_allowzero, + }, + info.child, + info.sentinel_ptr, + ), + else => @compileError(err), + } + }, + else => @compileError(err), + }; +} + +const std = @import("std"); diff --git a/zigversion/before16.zig b/zigversion/before16.zig new file mode 100644 index 0000000..50c5ec4 --- /dev/null +++ b/zigversion/before16.zig @@ -0,0 +1,53 @@ +pub const Slice = @import("slicebefore16.zig").Slice; +pub const SliceWithMaxLen = @import("slicebefore16.zig").SliceWithMaxLen; + +pub fn NonExhaustive(comptime T: type) type { + const info = switch (@typeInfo(T)) { + .@"enum" => |info| info, + else => |info| @compileError("expected an Enum type but got a(n) " ++ @tagName(info)), + }; + std.debug.assert(info.is_exhaustive); + return @Type(std.builtin.Type{ .@"enum" = .{ + .tag_type = info.tag_type, + .fields = info.fields, + .decls = &.{}, + .is_exhaustive = false, + } }); +} + +pub fn ArrayPointer(comptime T: type) type { + const err = "ArrayPointer not implemented for " ++ @typeName(T); + return switch (@typeInfo(T)) { + .pointer => |info| { + switch (info.size) { + .one => switch (@typeInfo(info.child)) { + .Array => |array_info| @Type(std.builtin.Type{ .pointer = .{ + .size = .Many, + .is_const = true, + .is_volatile = false, + .alignment = @alignOf(array_info.child), + .address_space = info.address_space, + .child = array_info.child, + .is_allowzero = false, + .sentinel = array_info.sentinel, + } }), + else => @compileError(err), + }, + .slice => @Type(std.builtin.Type{ .pointer = .{ + .size = .many, + .is_const = info.is_const, + .is_volatile = info.is_volatile, + .alignment = info.alignment, + .address_space = info.address_space, + .child = info.child, + .is_allowzero = info.is_allowzero, + .sentinel_ptr = info.sentinel_ptr, + } }), + else => @compileError(err), + } + }, + else => @compileError(err), + }; +} + +const std = @import("std"); diff --git a/zigversion/sliceatleast16.zig b/zigversion/sliceatleast16.zig new file mode 100644 index 0000000..76b2e38 --- /dev/null +++ b/zigversion/sliceatleast16.zig @@ -0,0 +1,107 @@ +const std = @import("std"); + +pub fn Slice(comptime LenType: type, comptime Ptr: type) type { + return struct { + const Self = @This(); + const ptr_info = @typeInfo(Ptr).pointer; + pub const NativeSlice = @Pointer( + .slice, + .{ + .@"const" = ptr_info.is_const, + .@"volatile" = ptr_info.is_volatile, + .@"align" = ptr_info.alignment, + .@"addrspace" = ptr_info.address_space, + .@"allowzero" = ptr_info.is_allowzero, + }, + ptr_info.child, + ptr_info.sentinel(), + ); + + ptr: Ptr, + len: LenType, + + pub const empty: @This() = .{ .ptr = undefined, .len = 0 }; + + pub fn init(ptr: Ptr, len: LenType) @This() { + return .{ .ptr = ptr, .len = len }; + } + + pub fn initAssume(slice: NativeSlice) @This() { + return .{ .ptr = slice.ptr, .len = @intCast(slice.len) }; + } + + pub fn initComptime(comptime ct_slice: NativeSlice) @This() { + return .{ .ptr = ct_slice.ptr, .len = @intCast(ct_slice.len) }; + } + + pub fn nativeSlice(self: @This()) NativeSlice { + return self.ptr[0..self.len]; + } + + pub fn lenCast(self: @This(), comptime NewLenType: type) Slice(NewLenType, Ptr) { + return .{ .ptr = self.ptr, .len = @intCast(self.len) }; + } + + pub const format = switch (@typeInfo(Ptr).pointer.child) { + u8 => (struct { + pub fn format(self: Self, writer: *std.Io.Writer) error{WriteFailed}!void { + try writer.writeAll(self.ptr[0..self.len]); + } + }).format, + else => @compileError("can't format non-u8 slice"), + }; + }; +} + +pub fn SliceWithMaxLen(comptime LenType: type, comptime Ptr: type, comptime max_len_arg: LenType) type { + return struct { + pub const max_len = max_len_arg; + pub const undefined_max_len: @This() = .{ .ptr = undefined, .len = max_len }; + + const Self = @This(); + const ptr_info = @typeInfo(Ptr).pointer; + pub const NativeSlice = @Pointer( + .slice, + .{ + .@"const" = ptr_info.is_const, + .@"volatile" = ptr_info.is_volatile, + .@"align" = ptr_info.alignment, + .@"addrspace" = ptr_info.address_space, + .@"allowzero" = ptr_info.is_allowzero, + }, + ptr_info.child, + ptr_info.sentinel(), + ); + + ptr: Ptr, + len: LenType, + + pub const empty: @This() = .{ .ptr = undefined, .len = 0 }; + + pub fn validateMaxLen(self: @This()) void { + std.debug.assert(self.len <= max_len); + } + + pub fn nativeSlice(self: @This()) NativeSlice { + return self.ptr[0..self.len]; + } + + pub fn initComptime(comptime ct_slice: NativeSlice) @This() { + std.debug.assert(ct_slice.len <= max_len); + return .{ .ptr = ct_slice.ptr, .len = @intCast(ct_slice.len) }; + } + + pub fn lenCast(self: @This(), comptime NewLenType: type) Slice(NewLenType, Ptr) { + return .{ .ptr = self.ptr, .len = @intCast(self.len) }; + } + + pub const format = switch (@typeInfo(Ptr).pointer.child) { + u8 => (struct { + pub fn format(self: Self, writer: *std.Io.Writer) error{WriteFailed}!void { + try writer.writeAll(self.ptr[0..self.len]); + } + }).format, + else => @compileError("can't format non-u8 slice"), + }; + }; +} diff --git a/src/x/slice.zig b/zigversion/slicebefore16.zig similarity index 100% rename from src/x/slice.zig rename to zigversion/slicebefore16.zig