diff options
| -rw-r--r-- | sqlite.zig | 44 |
1 files changed, 38 insertions, 6 deletions
| @@ -30,11 +30,43 @@ test { | |||
| 30 | 30 | ||
| 31 | const logger = std.log.scoped(.sqlite); | 31 | const logger = std.log.scoped(.sqlite); |
| 32 | 32 | ||
| 33 | fn isStruct(comptime typ: type) bool { | 33 | // Returns true if the passed type is a struct. |
| 34 | const type_info = @typeInfo(typ); | 34 | fn 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. | ||
| 42 | fn 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. |
| 39 | pub const Text = struct { data: []const u8 }; | 71 | pub 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)); |