aws-sdk-for-zig/src/url.zig

97 lines
3.4 KiB
Zig
Raw Normal View History

const std = @import("std");
pub fn encode(obj: anytype, writer: anytype, options: anytype) !void {
try encodeStruct("", obj, writer, options);
}
fn encodeStruct(parent: []const u8, obj: anytype, writer: anytype, options: anytype) !void {
var first = true;
inline for (@typeInfo(@TypeOf(obj)).Struct.fields) |field| {
const field_name = if (@hasField(@TypeOf(options), "field_name_transformer")) try options.field_name_transformer.transform(field.name) else field.name;
defer {
if (@hasField(@TypeOf(options), "field_name_transformer"))
options.field_name_transformer.transform_deinit(field_name);
}
if (!first) _ = try writer.write("&");
switch (@typeInfo(field.field_type)) {
.Struct => {
try encodeStruct(field_name ++ ".", @field(obj, field.name), writer);
},
else => try writer.print("{s}{s}={s}", .{ parent, field_name, @field(obj, field.name) }),
}
first = false;
}
}
fn testencode(expected: []const u8, value: anytype, options: anytype) !void {
const ValidationWriter = struct {
const Self = @This();
pub const Writer = std.io.Writer(*Self, Error, write);
pub const Error = error{
TooMuchData,
DifferentData,
};
expected_remaining: []const u8,
fn init(exp: []const u8) Self {
return .{ .expected_remaining = exp };
}
pub fn writer(self: *Self) Writer {
return .{ .context = self };
}
fn write(self: *Self, bytes: []const u8) Error!usize {
// std.debug.print("{s}", .{bytes});
if (self.expected_remaining.len < bytes.len) {
std.debug.warn(
\\====== expected this output: =========
\\{s}
\\======== instead found this: =========
\\{s}
\\======================================
, .{
self.expected_remaining,
bytes,
});
return error.TooMuchData;
}
if (!std.mem.eql(u8, self.expected_remaining[0..bytes.len], bytes)) {
std.debug.warn(
\\====== expected this output: =========
\\{s}
\\======== instead found this: =========
\\{s}
\\======================================
, .{
self.expected_remaining[0..bytes.len],
bytes,
});
return error.DifferentData;
}
self.expected_remaining = self.expected_remaining[bytes.len..];
return bytes.len;
}
};
var vos = ValidationWriter.init(expected);
try encode(value, vos.writer(), options);
if (vos.expected_remaining.len > 0) return error.NotEnoughData;
}
test "can url encode an object" {
try testencode(
"Action=GetCallerIdentity&Version=2021-01-01",
.{ .Action = "GetCallerIdentity", .Version = "2021-01-01" },
.{},
);
}
test "can url encode a complex object" {
try testencode(
"Action=GetCallerIdentity&Version=2021-01-01&complex.innermember=foo",
.{ .Action = "GetCallerIdentity", .Version = "2021-01-01", .complex = .{ .innermember = "foo" } },
.{},
);
}