added pointless file so I can work more later on

This commit is contained in:
ajpd 2025-04-11 17:06:01 -05:00
parent 6d08a9f19e
commit 6c52977189
2 changed files with 177 additions and 2 deletions

172
src/json-helper.zig Normal file
View File

@ -0,0 +1,172 @@
//! ISC License
//!
//! Copyright (c) 2024-2025 Yuzu
//!
//! Permission to use, copy, modify, and/or distribute this software for any
//! purpose with or without fee is hereby granted, provided that the above
//! copyright notice and this permission notice appear in all copies.
//!
//! THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
//! REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
//! AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
//! INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
//! LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
//! OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
//! PERFORMANCE OF THIS SOFTWARE.
const std = @import("std");
/// a hashmap for key value pairs
/// where every key is an int
///
/// an example would be this
///
/// {
/// ...
/// "integration_types_config": {
/// "0": ...
/// "1": {
/// "oauth2_install_params": {
/// "scopes": ["applications.commands"],
/// "permissions": "0"
/// }
/// }
/// },
/// ...
/// }
/// this would help us map an enum member 0, 1, etc of type E into V
/// very useful stuff
/// internally, an EnumMap
pub fn AssociativeArray(comptime E: type, comptime V: type) type {
if (@typeInfo(E) != .@"enum")
@compileError("may only use enums as keys");
return struct {
map: std.EnumMap(E, V),
pub fn jsonParse(allocator: std.mem.Allocator, src: []const u8) !@This() {
const scanner = std.json.Scanner.initCompleteInput(allocator, src);
defer scanner.deinit();
var map: std.EnumMap(E, V) = .{};
if (try scanner.next() != .object_begin)
return error.InvalidJson;
while (true) {
switch (try scanner.peekNextTokenType()) {
.object_end => break,
.string => {}, // might be a key
else => return error.UnexpectedToken,
}
const key = try std.json.innerParse(E, allocator, &scanner, .{
.max_value_len = 0x100
});
const val = try std.json.innerParse(V, allocator, &scanner, .{
.max_value_len = 0x100
});
if (map.contains(key))
return error.DuplicateKey;
map.put(key, val);
}
return .{.map = map};
}
};
}
/// assumes object.value[key] is of type `E` and the result thereof maps to the tagged union value
/// assumes `key` is a field present in all members of type `U`
/// eg: `type` is a property of type E and E.User maps to a User struct, whereas E.Admin maps to an Admin struct
pub fn DiscriminatedUnion(comptime U: type, comptime key: []const u8) type {
if (@typeInfo(U) != .@"union")
@compileError("may only cast a union");
if (@typeInfo(U).@"union".tag_type == null)
@compileError("cannot cast untagged union");
const E = comptime @typeInfo(U).@"union".tag_type.?;
if (@typeInfo(U).@"union".tag_type.? != E)
@compileError("enum tag type of union(" ++ @typeName(U.@"union".tag_type) ++ ") doesn't match " ++ @typeName(E));
return struct {
t: U,
pub fn jsonParse(allocator: std.mem.Allocator, src: []const u8) !@This() {
const scanner = std.json.Scanner.initCompleteInput(allocator, src);
defer scanner.deinit();
if (try scanner.next() != .object_begin)
return error.CouldntMatchAgainstNonObjectType;
// extract next value, which should be an object
// and should have a key "type" or whichever key might be
const value = try std.json.innerParse(std.json.Value, allocator, &scanner, .{
.max_value_len = 0x100
});
if (value != .object)
return error.CouldntMatchAgainstNonObjectType;
const discriminator = value.object.get(key) orelse
@panic("couldn't find property " ++ key ++ "in raw object");
var u: U = undefined;
if (discriminator != .integer)
return error.CouldntMatchAgainstNonIntegerType;
const tag: @typeInfo(E).@"enum".tag_type = @intCast(discriminator.integer);
inline for (@typeInfo(E).@"enum".fields) |field| {
if (field.value == tag) {
const T = comptime std.meta.fields(U)[field.value].type;
comptime std.debug.assert(@hasField(T, key));
u = @unionInit(U, field.name, try std.json.innerParse(T, allocator, &scanner, .{.max_value_len = 0x100}));
}
}
return .{ .t = u };
}
};
}
/// a hashmap for key value pairs
pub fn Record(comptime T: type) type {
return struct {
map: std.StringHashMapUnmanaged(T),
pub fn jsonParse(allocator: std.mem.Allocator, src: []const u8) !@This() {
const scanner = std.json.Scanner.initCompleteInput(allocator, src);
defer scanner.deinit();
const value = try std.json.innerParse(std.json.Value, allocator, &scanner, .{
.max_value_len = 0x100
});
if (value != .object)
return error.CouldntMatchAgainstNonObjectType;
errdefer value.object.deinit();
var iterator = value.object.iterator();
var map: std.StringHashMapUnmanaged(T) = .init;
while (iterator.next()) |pair| {
const k = pair.key_ptr.*;
const v = pair.value_ptr.*;
// might leak because std.json is retarded
// errdefer allocator.free(k);
// errdefer v.deinit(allocator);
try map.put(allocator, k, try std.json.parseFromValue(T, allocator, v, .{ .max_value_len =0x100}));
}
return .{ .map = map };
}
};
}

View File

@ -376,10 +376,13 @@ pub const CloseError = mem.Allocator.Error || error{ReasonTooLong};
pub fn close(self: *Self, code: ShardSocketCloseCodes, reason: []const u8) CloseError!void {
// Implement reconnection logic here
try self.client.close(.{
self.client.close(.{
.code = @intFromEnum(code), //u16
.reason = reason, //[]const u8
});
}) catch {
// log that the connection died, but don't stop the bot
self.logif("Shard {d} closed with error: {s} # {d}", .{self.id, reason, @intFromEnum(code)});
};
}
pub const SendError = net.Stream.WriteError || std.ArrayList(u8).Writer.Error;