mirror of
https://git.xeondev.com/LR/S.git
synced 2026-02-04 23:12:19 +01:00
Release 0.1.0
This commit is contained in:
90
common/src/args.zig
Normal file
90
common/src/args.zig
Normal file
@@ -0,0 +1,90 @@
|
||||
const std = @import("std");
|
||||
const meta = std.meta;
|
||||
const enums = std.enums;
|
||||
|
||||
const Allocator = std.mem.Allocator;
|
||||
const ArenaAllocator = std.heap.ArenaAllocator;
|
||||
|
||||
pub fn Parsed(comptime Args: type) type {
|
||||
return struct {
|
||||
const P = @This();
|
||||
|
||||
arena: ArenaAllocator,
|
||||
options: Args,
|
||||
|
||||
pub fn deinit(p: P) void {
|
||||
p.arena.deinit();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub fn parseOrPrintUsageAlloc(comptime Args: type, gpa: std.mem.Allocator, args: std.process.Args) ?Parsed(Args) {
|
||||
var arena: ArenaAllocator = .init(gpa);
|
||||
const args_slice = args.toSlice(arena.allocator()) catch return null;
|
||||
|
||||
const parsed_args = parse(Args, args_slice[1..]) orelse {
|
||||
printUsage(Args, args_slice[0]);
|
||||
arena.deinit();
|
||||
return null;
|
||||
};
|
||||
|
||||
return .{
|
||||
.arena = arena,
|
||||
.options = parsed_args,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn parse(comptime Args: type, args: []const [:0]const u8) ?Args {
|
||||
const fields = @typeInfo(Args).@"struct".fields;
|
||||
const ArgField = comptime meta.FieldEnum(Args);
|
||||
const Flag = comptime blk: {
|
||||
const field_names = meta.fieldNames(ArgField);
|
||||
var flags: [field_names.len]u8 = undefined;
|
||||
|
||||
for (field_names, 0..) |name, i| {
|
||||
flags[i] = name[0];
|
||||
}
|
||||
|
||||
break :blk @Enum(u8, .exhaustive, field_names, &flags);
|
||||
};
|
||||
|
||||
var result: Args = .{};
|
||||
|
||||
var arg_stack_buffer: [fields.len]Flag = undefined;
|
||||
var arg_stack = std.ArrayList(Flag).initBuffer(arg_stack_buffer[0..]);
|
||||
|
||||
for (args) |arg| {
|
||||
if (arg[0] == '-') {
|
||||
for (arg[1..]) |flag| {
|
||||
if (arg_stack.items.len == fields.len) return null;
|
||||
arg_stack.appendAssumeCapacity(std.enums.fromInt(Flag, flag) orelse return null);
|
||||
}
|
||||
} else {
|
||||
if (arg_stack.items.len == 0) return null;
|
||||
switch (arg_stack.swapRemove(0)) {
|
||||
inline else => |flag| @field(result, @tagName(flag)) = arg,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return if (arg_stack.items.len == 0) result else null;
|
||||
}
|
||||
|
||||
pub fn printUsage(comptime Args: type, program_name: []const u8) void {
|
||||
const usage_string = comptime blk: {
|
||||
var fmt: []const u8 = "Usage: {s} [-";
|
||||
for (@typeInfo(Args).@"struct".fields) |field| {
|
||||
fmt = fmt ++ .{field.name[0]};
|
||||
}
|
||||
|
||||
fmt = fmt ++ "] ";
|
||||
|
||||
for (@typeInfo(Args).@"struct".fields) |field| {
|
||||
fmt = fmt ++ "[" ++ field.name ++ "] ";
|
||||
}
|
||||
|
||||
break :blk fmt ++ "\n";
|
||||
};
|
||||
|
||||
std.debug.print(usage_string, .{program_name});
|
||||
}
|
||||
1
common/src/io.zig
Normal file
1
common/src/io.zig
Normal file
@@ -0,0 +1 @@
|
||||
pub const Poll = @import("io/poll.zig").Poll;
|
||||
2605
common/src/io/poll.zig
Normal file
2605
common/src/io/poll.zig
Normal file
File diff suppressed because it is too large
Load Diff
47
common/src/mem.zig
Normal file
47
common/src/mem.zig
Normal file
@@ -0,0 +1,47 @@
|
||||
const std = @import("std");
|
||||
|
||||
pub fn LimitedString(comptime limit: usize) type {
|
||||
return struct {
|
||||
const String = @This();
|
||||
|
||||
pub const max_length = limit;
|
||||
pub const empty: String = .{};
|
||||
|
||||
bytes: [max_length + 1]u8 = @splat(0),
|
||||
|
||||
pub fn init(value: []const u8) error{TooLongString}!String {
|
||||
var string: String = .{};
|
||||
try string.set(value);
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
pub fn constant(comptime value: []const u8) String {
|
||||
errdefer comptime unreachable; // Constant string literal is too long.
|
||||
return try comptime String.init(value);
|
||||
}
|
||||
|
||||
pub fn view(string: *const String) [:0]const u8 {
|
||||
std.debug.assert(string.bytes[max_length] == 0);
|
||||
return std.mem.span(@as([*:0]const u8, @ptrCast(&string.bytes)));
|
||||
}
|
||||
|
||||
pub fn set(string: *String, value: []const u8) error{TooLongString}!void {
|
||||
if (value.len > max_length) return error.TooLongString;
|
||||
|
||||
@memcpy(string.bytes[0..value.len], value);
|
||||
string.bytes[value.len] = 0;
|
||||
}
|
||||
|
||||
pub fn jsonStringify(string: *const String, jws: anytype) !void {
|
||||
try jws.write(string.view());
|
||||
}
|
||||
|
||||
pub fn jsonParse(a: std.mem.Allocator, source: anytype, options: std.json.ParseOptions) !String {
|
||||
return switch (try source.nextAlloc(a, options.allocate.?)) {
|
||||
inline .string, .allocated_string => |string| String.init(string) catch error.LengthMismatch,
|
||||
else => return error.UnexpectedToken,
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
3
common/src/root.zig
Normal file
3
common/src/root.zig
Normal file
@@ -0,0 +1,3 @@
|
||||
pub const io = @import("io.zig");
|
||||
pub const args = @import("args.zig");
|
||||
pub const mem = @import("mem.zig");
|
||||
Reference in New Issue
Block a user