const std = @import("../std.zig");
const testing = std.testing;
const valgrind = std.valgrind;
pub const MemCheckClientRequest = enum(usize) {
    MakeMemNoAccess = valgrind.ToolBase("MC".*),
    MakeMemUndefined,
    MakeMemDefined,
    Discard,
    CheckMemIsAddressable,
    CheckMemIsDefined,
    DoLeakCheck,
    CountLeaks,
    GetVbits,
    SetVbits,
    CreateBlock,
    MakeMemDefinedIfAddressable,
    CountLeakBlocks,
    EnableAddrErrorReportingInRange,
    DisableAddrErrorReportingInRange,
};
fn doMemCheckClientRequestExpr(default: usize, request: MemCheckClientRequest, a1: usize, a2: usize, a3: usize, a4: usize, a5: usize) usize {
    return valgrind.doClientRequest(default, @intCast(usize, @enumToInt(request)), a1, a2, a3, a4, a5);
}
fn doMemCheckClientRequestStmt(request: MemCheckClientRequest, a1: usize, a2: usize, a3: usize, a4: usize, a5: usize) void {
    _ = doMemCheckClientRequestExpr(0, request, a1, a2, a3, a4, a5);
}
pub fn makeMemNoAccess(qzz: []u8) i1 {
    return @intCast(i1, doMemCheckClientRequestExpr(0, 
        .MakeMemNoAccess, @ptrToInt(qzz.ptr), qzz.len, 0, 0, 0));
}
pub fn makeMemUndefined(qzz: []u8) i1 {
    return @intCast(i1, doMemCheckClientRequestExpr(0, 
        .MakeMemUndefined, @ptrToInt(qzz.ptr), qzz.len, 0, 0, 0));
}
pub fn makeMemDefined(qzz: []u8) i1 {
    
    return @intCast(i1, doMemCheckClientRequestExpr(0, 
        .MakeMemDefined, @ptrToInt(qzz.ptr), qzz.len, 0, 0, 0));
}
pub fn makeMemDefinedIfAddressable(qzz: []u8) i1 {
    return @intCast(i1, doMemCheckClientRequestExpr(0, 
        .MakeMemDefinedIfAddressable, @ptrToInt(qzz.ptr), qzz.len, 0, 0, 0));
}
pub fn createBlock(qzz: []u8, desc: [*]u8) usize {
    return doMemCheckClientRequestExpr(0, 
        .CreateBlock, @ptrToInt(qzz.ptr), qzz.len, @ptrToInt(desc), 0, 0);
}
pub fn discard(blkindex: usize) bool {
    return doMemCheckClientRequestExpr(0, 
        .Discard, 0, blkindex, 0, 0, 0) != 0;
}
pub fn checkMemIsAddressable(qzz: []u8) usize {
    return doMemCheckClientRequestExpr(0, .CheckMemIsAddressable, @ptrToInt(qzz.ptr), qzz.len, 0, 0, 0);
}
pub fn checkMemIsDefined(qzz: []u8) usize {
    return doMemCheckClientRequestExpr(0, .CheckMemIsDefined, @ptrToInt(qzz.ptr), qzz.len, 0, 0, 0);
}
pub fn doLeakCheck() void {
    doMemCheckClientRequestStmt(.DO_LEAK_CHECK, 0, 0, 0, 0, 0);
}
pub fn doAddedLeakCheck() void {
    doMemCheckClientRequestStmt(.DO_LEAK_CHECK, 0, 1, 0, 0, 0);
}
pub fn doChangedLeakCheck() void {
    doMemCheckClientRequestStmt(.DO_LEAK_CHECK, 0, 2, 0, 0, 0);
}
pub fn doQuickLeakCheck() void {
    doMemCheckClientRequestStmt(.DO_LEAK_CHECK, 1, 0, 0, 0, 0);
}
const CountResult = struct {
    leaked: usize,
    dubious: usize,
    reachable: usize,
    suppressed: usize,
};
pub fn countLeaks() CountResult {
    var res: CountResult = .{
        .leaked = 0,
        .dubious = 0,
        .reachable = 0,
        .suppressed = 0,
    };
    doMemCheckClientRequestStmt(
        .CountLeaks,
        @ptrToInt(&res.leaked),
        @ptrToInt(&res.dubious),
        @ptrToInt(&res.reachable),
        @ptrToInt(&res.suppressed),
        0,
    );
    return res;
}
test "countLeaks" {
    try testing.expectEqual(
        @as(CountResult, .{
            .leaked = 0,
            .dubious = 0,
            .reachable = 0,
            .suppressed = 0,
        }),
        countLeaks(),
    );
}
pub fn countLeakBlocks() CountResult {
    var res: CountResult = .{
        .leaked = 0,
        .dubious = 0,
        .reachable = 0,
        .suppressed = 0,
    };
    doMemCheckClientRequestStmt(
        .CountLeakBlocks,
        @ptrToInt(&res.leaked),
        @ptrToInt(&res.dubious),
        @ptrToInt(&res.reachable),
        @ptrToInt(&res.suppressed),
        0,
    );
    return res;
}
test "countLeakBlocks" {
    try testing.expectEqual(
        @as(CountResult, .{
            .leaked = 0,
            .dubious = 0,
            .reachable = 0,
            .suppressed = 0,
        }),
        countLeakBlocks(),
    );
}
pub fn getVbits(zza: []u8, zzvbits: []u8) u2 {
    std.debug.assert(zzvbits.len >= zza.len / 8);
    return @intCast(u2, doMemCheckClientRequestExpr(0, .GetVbits, @ptrToInt(zza.ptr), @ptrToInt(zzvbits), zza.len, 0, 0));
}
pub fn setVbits(zzvbits: []u8, zza: []u8) u2 {
    std.debug.assert(zzvbits.len >= zza.len / 8);
    return @intCast(u2, doMemCheckClientRequestExpr(0, .SetVbits, @ptrToInt(zza.ptr), @ptrToInt(zzvbits), zza.len, 0, 0));
}
pub fn disableAddrErrorReportingInRange(qzz: []u8) usize {
    return doMemCheckClientRequestExpr(0, 
        .DisableAddrErrorReportingInRange, @ptrToInt(qzz.ptr), qzz.len, 0, 0, 0);
}
pub fn enableAddrErrorReportingInRange(qzz: []u8) usize {
    return doMemCheckClientRequestExpr(0, 
        .EnableAddrErrorReportingInRange, @ptrToInt(qzz.ptr), qzz.len, 0, 0, 0);
}