Add utility functions to make function pointer casting more safe.

It's now only changing the self parameter, everything else will be checked at compile-time.

fixes #1223
This commit is contained in:
IntegratedQuantum 2025-03-22 21:23:32 +01:00
parent 5845da7ca9
commit ac9f00cb32
8 changed files with 64 additions and 35 deletions

View File

@ -125,10 +125,10 @@ const MusicLoadTask = struct {
musicId: []const u8,
const vtable = utils.ThreadPool.VTable{
.getPriority = @ptrCast(&getPriority),
.isStillNeeded = @ptrCast(&isStillNeeded),
.run = @ptrCast(&run),
.clean = @ptrCast(&clean),
.getPriority = main.utils.castFunctionSelfToAnyopaque(getPriority),
.isStillNeeded = main.utils.castFunctionSelfToAnyopaque(isStillNeeded),
.run = main.utils.castFunctionSelfToAnyopaque(run),
.clean = main.utils.castFunctionSelfToAnyopaque(clean),
.taskType = .misc,
};

View File

@ -130,10 +130,10 @@ pub const Gamepad = struct {
curTimestamp: i128,
var running = std.atomic.Value(bool).init(false);
const vtable = main.utils.ThreadPool.VTable{
.getPriority = @ptrCast(&getPriority),
.isStillNeeded = @ptrCast(&isStillNeeded),
.run = @ptrCast(&run),
.clean = @ptrCast(&clean),
.getPriority = main.utils.castFunctionSelfToAnyopaque(getPriority),
.isStillNeeded = main.utils.castFunctionSelfToAnyopaque(isStillNeeded),
.run = main.utils.castFunctionSelfToAnyopaque(run),
.clean = main.utils.castFunctionSelfToAnyopaque(clean),
};
pub fn schedule(curTimestamp: i128) void {

View File

@ -1816,10 +1816,10 @@ const ProtocolTask = struct {
data: []const u8,
const vtable = utils.ThreadPool.VTable{
.getPriority = @ptrCast(&getPriority),
.isStillNeeded = @ptrCast(&isStillNeeded),
.run = @ptrCast(&run),
.clean = @ptrCast(&clean),
.getPriority = main.utils.castFunctionSelfToAnyopaque(getPriority),
.isStillNeeded = main.utils.castFunctionSelfToAnyopaque(isStillNeeded),
.run = main.utils.castFunctionSelfToAnyopaque(run),
.clean = main.utils.castFunctionSelfToAnyopaque(clean),
.taskType = .misc,
};

View File

@ -707,10 +707,10 @@ pub const ChunkMesh = struct { // MARK: ChunkMesh
mesh: *ChunkMesh,
pub const vtable = main.utils.ThreadPool.VTable{
.getPriority = @ptrCast(&getPriority),
.isStillNeeded = @ptrCast(&isStillNeeded),
.run = @ptrCast(&run),
.clean = @ptrCast(&clean),
.getPriority = main.utils.castFunctionSelfToAnyopaque(getPriority),
.isStillNeeded = main.utils.castFunctionSelfToAnyopaque(isStillNeeded),
.run = main.utils.castFunctionSelfToAnyopaque(run),
.clean = main.utils.castFunctionSelfToAnyopaque(clean),
.taskType = .misc,
};

View File

@ -896,10 +896,10 @@ pub const MeshGenerationTask = struct { // MARK: MeshGenerationTask
mesh: *chunk.Chunk,
pub const vtable = utils.ThreadPool.VTable{
.getPriority = @ptrCast(&getPriority),
.isStillNeeded = @ptrCast(&isStillNeeded),
.run = @ptrCast(&run),
.clean = @ptrCast(&clean),
.getPriority = main.utils.castFunctionSelfToAnyopaque(getPriority),
.isStillNeeded = main.utils.castFunctionSelfToAnyopaque(isStillNeeded),
.run = main.utils.castFunctionSelfToAnyopaque(run),
.clean = main.utils.castFunctionSelfToAnyopaque(clean),
.taskType = .meshgenAndLighting,
};

View File

@ -60,9 +60,9 @@ pub const SimpleStructureModel = struct { // MARK: SimpleStructureModel
pub fn registerGenerator(comptime Generator: type) void {
var self: VTable = undefined;
self.loadModel = @ptrCast(&Generator.loadModel);
self.generate = @ptrCast(&Generator.generate);
self.hashFunction = @ptrCast(&struct {
self.loadModel = main.utils.castFunctionReturnToAnyopaque(Generator.loadModel);
self.generate = main.utils.castFunctionSelfToAnyopaque(Generator.generate);
self.hashFunction = main.utils.castFunctionSelfToAnyopaque(struct {
fn hash(ptr: *Generator) u64 {
return hashGeneric(ptr.*);
}

View File

@ -134,10 +134,10 @@ const ChunkManager = struct { // MARK: ChunkManager
source: Source,
const vtable = utils.ThreadPool.VTable{
.getPriority = @ptrCast(&getPriority),
.isStillNeeded = @ptrCast(&isStillNeeded),
.run = @ptrCast(&run),
.clean = @ptrCast(&clean),
.getPriority = main.utils.castFunctionSelfToAnyopaque(getPriority),
.isStillNeeded = main.utils.castFunctionSelfToAnyopaque(isStillNeeded),
.run = main.utils.castFunctionSelfToAnyopaque(run),
.clean = main.utils.castFunctionSelfToAnyopaque(clean),
.taskType = .chunkgen,
};
@ -194,10 +194,10 @@ const ChunkManager = struct { // MARK: ChunkManager
source: ?*User,
const vtable = utils.ThreadPool.VTable{
.getPriority = @ptrCast(&getPriority),
.isStillNeeded = @ptrCast(&isStillNeeded),
.run = @ptrCast(&run),
.clean = @ptrCast(&clean),
.getPriority = main.utils.castFunctionSelfToAnyopaque(getPriority),
.isStillNeeded = main.utils.castFunctionSelfToAnyopaque(isStillNeeded),
.run = main.utils.castFunctionSelfToAnyopaque(run),
.clean = main.utils.castFunctionSelfToAnyopaque(clean),
.taskType = .misc,
};
@ -583,10 +583,10 @@ pub const ServerWorld = struct { // MARK: ServerWorld
storeMaps: bool,
const vtable = utils.ThreadPool.VTable{
.getPriority = @ptrCast(&getPriority),
.isStillNeeded = @ptrCast(&isStillNeeded),
.run = @ptrCast(&run),
.clean = @ptrCast(&clean),
.getPriority = main.utils.castFunctionSelfToAnyopaque(getPriority),
.isStillNeeded = main.utils.castFunctionSelfToAnyopaque(isStillNeeded),
.run = main.utils.castFunctionSelfToAnyopaque(run),
.clean = main.utils.castFunctionSelfToAnyopaque(clean),
.taskType = .chunkgen,
};

View File

@ -1494,3 +1494,32 @@ pub const BinaryWriter = struct {
self.data.append(delimiter);
}
};
// MARK: functionPtrCast()
fn CastFunctionSelfToAnyopaqueType(Fn: type) type {
var typeInfo = @typeInfo(Fn);
var params = typeInfo.@"fn".params[0..typeInfo.@"fn".params.len].*;
if(@sizeOf(params[0].type.?) != @sizeOf(*anyopaque) or @alignOf(params[0].type.?) != @alignOf(*anyopaque)) {
@compileError(std.fmt.comptimePrint("Cannot convert {} to *anyopaque", .{params[0].type.?}));
}
params[0].type = *anyopaque;
typeInfo.@"fn".params = params[0..];
return @Type(typeInfo);
}
/// Turns the first parameter into a anyopaque*
pub fn castFunctionSelfToAnyopaque(function: anytype) *const CastFunctionSelfToAnyopaqueType(@TypeOf(function)) {
return @ptrCast(&function);
}
fn CastFunctionReturnToAnyopaqueType(Fn: type) type {
var typeInfo = @typeInfo(Fn);
if(@sizeOf(typeInfo.@"fn".return_type.?) != @sizeOf(*anyopaque) or @alignOf(typeInfo.@"fn".return_type.?) != @alignOf(*anyopaque)) {
@compileError(std.fmt.comptimePrint("Cannot convert {} to *anyopaque", .{typeInfo.@"fn".return_type.?}));
}
typeInfo.@"fn".return_type = *anyopaque;
return @Type(typeInfo);
}
/// Turns the return parameter into a anyopaque*
pub fn castFunctionReturnToAnyopaque(function: anytype) *const CastFunctionReturnToAnyopaqueType(@TypeOf(function)) {
return @ptrCast(&function);
}