-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
-
20
-
21
-
22
-
23
-
24
-
25
-
26
-
27
-
28
-
29
-
30
-
31
-
32
-
33
-
34
-
35
-
36
-
37
-
38
-
39
-
40
-
41
-
42
-
43
-
44
-
45
-
46
-
47
-
48
-
49
-
50
-
51
-
52
-
53
-
54
-
55
-
56
-
57
-
58
-
59
-
60
-
61
-
62
-
63
-
64
-
65
-
66
-
67
-
68
-
69
-
70
-
71
-
72
-
73
-
74
-
75
-
76
-
77
-
78
-
79
-
80
-
81
-
82
-
83
-
84
-
85
-
86
-
87
-
88
-
89
-
90
-
91
-
92
-
93
-
94
-
95
-
96
-
97
-
98
-
99
-
100
-
101
-
102
-
103
-
104
-
105
-
106
-
107
-
108
-
109
-
110
-
111
-
112
-
113
-
114
-
115
-
116
-
117
-
118
-
119
-
120
-
121
-
122
-
123
-
124
-
125
-
126
-
127
-
128
// SPDX-License-Identifier: MPL-2.0
// Copyright 2026 Shota FUJI
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
const std = @import("std");
pub const authorization = @import("./authorization.zig");
pub fn Server(comptime UserAttributes: type) type {
return struct {
pub const RunError = std.Io.Writer.Error;
pub fn run(init: std.process.Init, handlers: *const authorization.Handlers(UserAttributes)) RunError!void {
_ = handlers;
const stdout = std.Io.File.stdout();
defer stdout.close(init.io);
var writer_buf: [1024]u8 = undefined;
var writer = stdout.writer(init.io, &writer_buf);
try std.json.fmt(AttrDef(UserAttributes){}, .{}).format(&writer.interface);
try writer.interface.writeByte('\n');
try writer.interface.flush();
}
};
}
fn AttrDef(comptime T: type) type {
const t = switch (@typeInfo(T)) {
.@"struct" => |str| str,
else => |t| {
@compileError(std.fmt.comptimePrint("AttrDef only accepts struct, got {t}", .{t}));
},
};
return struct {
fn writeType(comptime R: type, comptime field: []const u8, jws: *std.json.Stringify) !void {
switch (@typeInfo(R)) {
.int => |int| {
if (int.signedness == .unsigned) {
@compileError(std.fmt.comptimePrint("Integer attribute cannot be unsigned: {s}", .{field}));
}
if (int.bits > 52) {
@compileError(std.fmt.comptimePrint("Maximum integer size is 52bit: {s}", .{field}));
}
try jws.objectField("type");
try jws.write("int");
},
.float => |float| {
if (float.bits > 52) {
@compileError(std.fmt.comptimePrint("Maximum float size is 52bit: {s}", .{field}));
}
try jws.objectField("type");
try jws.write("float");
},
.bool => {
try jws.objectField("type");
try jws.write("bool");
},
.pointer => |pointer| {
if (!pointer.is_const or pointer.child != u8 or pointer.size != .slice) {
@compileError(std.fmt.comptimePrint("Only supported pointer is []const u8: {s}", .{field}));
}
try jws.objectField("type");
try jws.write("string");
},
.@"enum" => |e| {
try jws.objectField("type");
try jws.write("enum");
try jws.objectField("options");
try jws.beginArray();
inline for (e.fields) |f| {
try jws.beginObject();
try jws.objectField("name");
try jws.write(f.name);
try jws.objectField("value");
try jws.write(f.value);
try jws.endObject();
}
try jws.endArray();
},
else => {
@compileError(std.fmt.comptimePrint("Unsupported attribute value type at {s}: {t}", .{ field, @typeInfo(T) }));
},
}
}
pub fn jsonStringify(_: @This(), jws: *std.json.Stringify) !void {
try jws.beginArray();
inline for (t.fields) |field| {
try jws.beginObject();
try jws.objectField("key");
try jws.write(field.name);
switch (@typeInfo(field.type)) {
.optional => |optional| {
try jws.objectField("optional");
try jws.write(true);
try writeType(optional.child, field.name, jws);
},
else => {
try writeType(field.type, field.name, jws);
},
}
try jws.endObject();
}
try jws.endArray();
}
};
}