164 lines
6.5 KiB
Zig
164 lines
6.5 KiB
Zig
//! This module is maintained by hand and is copied to the generated code directory
|
|
const std = @import("std");
|
|
const builtin = @import("builtin");
|
|
const testing = std.testing;
|
|
|
|
const root = @import("root");
|
|
pub const UnicodeMode = enum { ansi, wide, unspecified };
|
|
// WORKAROUND: https://github.com/ziglang/zig/issues/7979
|
|
// using root.UNICODE causes an erroneous dependency loop, so I'm hardcoding to .wide for now
|
|
pub const unicode_mode = UnicodeMode.wide;
|
|
//pub const unicode_mode : UnicodeMode = if (@hasDecl(root, "UNICODE")) (if (root.UNICODE) .wide else .ansi) else .unspecified;
|
|
|
|
pub const L = std.unicode.utf8ToUtf16LeStringLiteral;
|
|
|
|
pub usingnamespace switch (unicode_mode) {
|
|
.ansi => struct {
|
|
pub const TCHAR = u8;
|
|
pub fn _T(comptime str: []const u8) *const [str.len:0]u8 {
|
|
return str;
|
|
}
|
|
},
|
|
.wide => struct {
|
|
pub const TCHAR = u16;
|
|
pub const _T = L;
|
|
},
|
|
.unspecified => if (builtin.is_test) struct {} else struct {
|
|
pub const TCHAR = @compileError("'TCHAR' requires that UNICODE be set to true or false in the root module");
|
|
pub const _T = @compileError("'_T' requires that UNICODE be set to true or false in the root module");
|
|
},
|
|
};
|
|
|
|
pub const Arch = enum { X86, X64, Arm64 };
|
|
pub const arch: Arch = switch (builtin.target.cpu.arch) {
|
|
.x86 => .X86,
|
|
.x86_64 => .X64,
|
|
.arm, .armeb, .aarch64 => .Arm64,
|
|
else => @compileError("unhandled arch " ++ @tagName(builtin.target.cpu.arch)),
|
|
};
|
|
|
|
// TODO: this should probably be in the standard lib somewhere?
|
|
pub const Guid = extern union {
|
|
Ints: extern struct {
|
|
a: u32,
|
|
b: u16,
|
|
c: u16,
|
|
d: [8]u8,
|
|
},
|
|
Bytes: [16]u8,
|
|
|
|
const big_endian_hex_offsets = [16]u6{ 0, 2, 4, 6, 9, 11, 14, 16, 19, 21, 24, 26, 28, 30, 32, 34 };
|
|
const little_endian_hex_offsets = [16]u6{ 6, 4, 2, 0, 11, 9, 16, 14, 19, 21, 24, 26, 28, 30, 32, 34 };
|
|
const hex_offsets = switch (builtin.target.cpu.arch.endian()) {
|
|
.Big => big_endian_hex_offsets,
|
|
.Little => little_endian_hex_offsets,
|
|
};
|
|
|
|
pub fn initString(s: []const u8) Guid {
|
|
var guid = Guid{ .Bytes = undefined };
|
|
for (hex_offsets, 0..) |hex_offset, i| {
|
|
//guid.Bytes[i] = decodeHexByte(s[offset..offset+2]);
|
|
guid.Bytes[i] = decodeHexByte([2]u8{ s[hex_offset], s[hex_offset + 1] });
|
|
}
|
|
return guid;
|
|
}
|
|
};
|
|
comptime {
|
|
std.debug.assert(@sizeOf(Guid) == 16);
|
|
}
|
|
|
|
// TODO: is this in the standard lib somewhere?
|
|
fn hexVal(c: u8) u4 {
|
|
if (c <= '9') return @as(u4, @intCast(c - '0'));
|
|
if (c >= 'a') return @as(u4, @intCast(c + 10 - 'a'));
|
|
return @as(u4, @intCast(c + 10 - 'A'));
|
|
}
|
|
|
|
// TODO: is this in the standard lib somewhere?
|
|
fn decodeHexByte(hex: [2]u8) u8 {
|
|
return @as(u8, @intCast(hexVal(hex[0]))) << 4 | hexVal(hex[1]);
|
|
}
|
|
|
|
test "Guid" {
|
|
try testing.expect(std.mem.eql(u8, switch (builtin.target.cpu.arch.endian()) {
|
|
.Big => "\x01\x23\x45\x67\x89\xAB\xEF\x10\x32\x54\x76\x98\xba\xdc\xfe\x91",
|
|
.Little => "\x67\x45\x23\x01\xAB\x89\x10\xEF\x32\x54\x76\x98\xba\xdc\xfe\x91",
|
|
}, &Guid.initString("01234567-89AB-EF10-3254-7698badcfe91").Bytes));
|
|
}
|
|
|
|
pub const PropertyKey = extern struct {
|
|
fmtid: Guid,
|
|
pid: u32,
|
|
pub fn init(fmtid: []const u8, pid: u32) PropertyKey {
|
|
return .{
|
|
.fmtid = Guid.initString(fmtid),
|
|
.pid = pid,
|
|
};
|
|
}
|
|
};
|
|
|
|
pub fn FAILED(hr: @import("foundation.zig").HRESULT) bool {
|
|
return hr < 0;
|
|
}
|
|
pub fn SUCCEEDED(hr: @import("foundation.zig").HRESULT) bool {
|
|
return hr >= 0;
|
|
}
|
|
|
|
// These constants were removed from the metadata to allow each projection
|
|
// to define them however they like (see https://github.com/microsoft/win32metadata/issues/530)
|
|
pub const FALSE: @import("foundation.zig").BOOL = 0;
|
|
pub const TRUE: @import("foundation.zig").BOOL = 1;
|
|
|
|
/// Converts comptime values to the given type.
|
|
/// Note that this function is called at compile time rather than converting constant values earlier at code generation time.
|
|
/// The reason for doing it a compile time is because genzig.zig generates all constants as they are encountered which can
|
|
/// be before it knows the constant's type definition, so we delay the convession to compile-time where the compiler knows
|
|
/// all type definition.
|
|
pub fn typedConst(comptime T: type, comptime value: anytype) T {
|
|
return typedConst2(T, T, value);
|
|
}
|
|
|
|
pub fn typedConst2(comptime ReturnType: type, comptime SwitchType: type, comptime value: anytype) ReturnType {
|
|
const target_type_error = @as([]const u8, "typedConst cannot convert to " ++ @typeName(ReturnType));
|
|
const value_type_error = @as([]const u8, "typedConst cannot convert " ++ @typeName(@TypeOf(value)) ++ " to " ++ @typeName(ReturnType));
|
|
|
|
switch (@typeInfo(SwitchType)) {
|
|
.Int => |target_type_info| {
|
|
if (value >= std.math.maxInt(SwitchType)) {
|
|
if (target_type_info.signedness == .signed) {
|
|
const UnsignedT = @Type(std.builtin.Type{ .Int = .{ .signedness = .unsigned, .bits = target_type_info.bits } });
|
|
return @as(SwitchType, @bitCast(@as(UnsignedT, value)));
|
|
}
|
|
}
|
|
return value;
|
|
},
|
|
.Pointer => |target_type_info| switch (target_type_info.size) {
|
|
.One, .Many, .C => {
|
|
switch (@typeInfo(@TypeOf(value))) {
|
|
.ComptimeInt, .Int => {
|
|
const usize_value = if (value >= 0) value else @as(usize, @bitCast(@as(isize, value)));
|
|
return @as(ReturnType, @ptrFromInt(usize_value));
|
|
},
|
|
else => @compileError(value_type_error),
|
|
}
|
|
},
|
|
else => target_type_error,
|
|
},
|
|
.Optional => |target_type_info| switch (@typeInfo(target_type_info.child)) {
|
|
.Pointer => return typedConst2(ReturnType, target_type_info.child, value),
|
|
else => target_type_error,
|
|
},
|
|
.Enum => |_| switch (@typeInfo(@TypeOf(value))) {
|
|
.Int => return @as(ReturnType, @enumFromInt(value)),
|
|
else => target_type_error,
|
|
},
|
|
else => @compileError(target_type_error),
|
|
}
|
|
}
|
|
test "typedConst" {
|
|
try testing.expectEqual(@as(usize, @bitCast(@as(isize, -1))), @intFromPtr(typedConst(?*opaque {}, -1)));
|
|
try testing.expectEqual(@as(usize, @bitCast(@as(isize, -12))), @intFromPtr(typedConst(?*opaque {}, -12)));
|
|
try testing.expectEqual(@as(u32, 0xffffffff), typedConst(u32, 0xffffffff));
|
|
try testing.expectEqual(@as(i32, @bitCast(@as(u32, 0x80000000))), typedConst(i32, 0x80000000));
|
|
}
|