summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sqlite.zig44
1 files changed, 38 insertions, 6 deletions
diff --git a/sqlite.zig b/sqlite.zig
index 4fd06df..c3ecb84 100644
--- a/sqlite.zig
+++ b/sqlite.zig
@@ -30,11 +30,43 @@ test {
30 30
31const logger = std.log.scoped(.sqlite); 31const logger = std.log.scoped(.sqlite);
32 32
33fn isStruct(comptime typ: type) bool { 33// Returns true if the passed type is a struct.
34 const type_info = @typeInfo(typ); 34fn isStruct(comptime T: type) bool {
35 const type_info = @typeInfo(T);
35 return type_info == .Struct; 36 return type_info == .Struct;
36} 37}
37 38
39// Returns true if the passed type will coerce to []const u8.
40//
41// NOTE(vincent): this is straight from the Zig stdlib before it was removed.
42fn isZigString(comptime T: type) bool {
43 return comptime blk: {
44 // Only pointer types can be strings, no optionals
45 const info = @typeInfo(T);
46 if (info != .Pointer) break :blk false;
47
48 const ptr = &info.Pointer;
49 // Check for CV qualifiers that would prevent coerction to []const u8
50 if (ptr.is_volatile or ptr.is_allowzero) break :blk false;
51
52 // If it's already a slice, simple check.
53 if (ptr.size == .Slice) {
54 break :blk ptr.child == u8;
55 }
56
57 // Otherwise check if it's an array type that coerces to slice.
58 if (ptr.size == .One) {
59 const child = @typeInfo(ptr.child);
60 if (child == .Array) {
61 const arr = &child.Array;
62 break :blk arr.child == u8;
63 }
64 }
65
66 break :blk false;
67 };
68}
69
38/// Text is used to represent a SQLite TEXT value when binding a parameter or reading a column. 70/// Text is used to represent a SQLite TEXT value when binding a parameter or reading a column.
39pub const Text = struct { data: []const u8 }; 71pub const Text = struct { data: []const u8 };
40 72
@@ -1068,7 +1100,7 @@ pub fn Iterator(comptime Type: type) type {
1068 .Enum => |TI| { 1100 .Enum => |TI| {
1069 debug.assert(columns == 1); 1101 debug.assert(columns == 1);
1070 1102
1071 if (comptime std.meta.trait.isZigString(Type.BaseType)) { 1103 if (comptime isZigString(Type.BaseType)) {
1072 @compileError("cannot read into type " ++ @typeName(Type) ++ " ; BaseType " ++ @typeName(Type.BaseType) ++ " requires allocation, use nextAlloc or oneAlloc"); 1104 @compileError("cannot read into type " ++ @typeName(Type) ++ " ; BaseType " ++ @typeName(Type.BaseType) ++ " requires allocation, use nextAlloc or oneAlloc");
1073 } 1105 }
1074 1106
@@ -1150,7 +1182,7 @@ pub fn Iterator(comptime Type: type) type {
1150 1182
1151 const inner_value = try self.readField(Type.BaseType, .{ .allocator = allocator }, 0); 1183 const inner_value = try self.readField(Type.BaseType, .{ .allocator = allocator }, 0);
1152 1184
1153 if (comptime std.meta.trait.isZigString(Type.BaseType)) { 1185 if (comptime isZigString(Type.BaseType)) {
1154 // The inner value is never returned to the user, we must free it ourselves. 1186 // The inner value is never returned to the user, we must free it ourselves.
1155 defer allocator.free(inner_value); 1187 defer allocator.free(inner_value);
1156 1188
@@ -1438,7 +1470,7 @@ pub fn Iterator(comptime Type: type) type {
1438 .Enum => |TI| { 1470 .Enum => |TI| {
1439 const inner_value = try self.readField(FieldType.BaseType, options, i); 1471 const inner_value = try self.readField(FieldType.BaseType, options, i);
1440 1472
1441 if (comptime std.meta.trait.isZigString(FieldType.BaseType)) { 1473 if (comptime isZigString(FieldType.BaseType)) {
1442 // The inner value is never returned to the user, we must free it ourselves. 1474 // The inner value is never returned to the user, we must free it ourselves.
1443 defer options.allocator.free(inner_value); 1475 defer options.allocator.free(inner_value);
1444 1476
@@ -1648,7 +1680,7 @@ pub const DynamicStatement = struct {
1648 return convertResultToError(result); 1680 return convertResultToError(result);
1649 }, 1681 },
1650 .Enum => { 1682 .Enum => {
1651 if (comptime std.meta.trait.isZigString(FieldType.BaseType)) { 1683 if (comptime isZigString(FieldType.BaseType)) {
1652 try self.bindField(FieldType.BaseType, options, field_name, i, @tagName(field)); 1684 try self.bindField(FieldType.BaseType, options, field_name, i, @tagName(field));
1653 } else if (@typeInfo(FieldType.BaseType) == .Int) { 1685 } else if (@typeInfo(FieldType.BaseType) == .Int) {
1654 try self.bindField(FieldType.BaseType, options, field_name, i, @intFromEnum(field)); 1686 try self.bindField(FieldType.BaseType, options, field_name, i, @intFromEnum(field));