Compare commits
2 Commits
f5663fd84d
...
1fe39007c5
Author | SHA1 | Date | |
---|---|---|---|
1fe39007c5 | |||
c5cb3dde29 |
119
src/aws.zig
119
src/aws.zig
|
@ -9,7 +9,69 @@ const date = @import("date.zig");
|
||||||
const servicemodel = @import("servicemodel.zig");
|
const servicemodel = @import("servicemodel.zig");
|
||||||
const xml_shaper = @import("xml_shaper.zig");
|
const xml_shaper = @import("xml_shaper.zig");
|
||||||
|
|
||||||
const log = std.log.scoped(.aws);
|
const scoped_log = std.log.scoped(.aws);
|
||||||
|
|
||||||
|
/// control all logs directly/indirectly used by aws sdk. Not recommended for
|
||||||
|
/// use under normal circumstances, but helpful for times when the zig logging
|
||||||
|
/// controls are insufficient (e.g. use in build script)
|
||||||
|
pub fn globalLogControl(aws_level: std.log.Level, http_level: std.log.Level, signing_level: std.log.Level, off: bool) void {
|
||||||
|
const signing = @import("aws_signing.zig");
|
||||||
|
logs_off = off;
|
||||||
|
signing.logs_off = off;
|
||||||
|
awshttp.logs_off = off;
|
||||||
|
log_level = aws_level;
|
||||||
|
awshttp.log_level = http_level;
|
||||||
|
signing.log_level = signing_level;
|
||||||
|
}
|
||||||
|
/// Specifies logging level. This should not be touched unless the normal
|
||||||
|
/// zig logging capabilities are inaccessible (e.g. during a build)
|
||||||
|
pub var log_level: std.log.Level = .debug;
|
||||||
|
|
||||||
|
/// Turn off logging completely
|
||||||
|
pub var logs_off: bool = false;
|
||||||
|
const log = struct {
|
||||||
|
/// Log an error message. This log level is intended to be used
|
||||||
|
/// when something has gone wrong. This might be recoverable or might
|
||||||
|
/// be followed by the program exiting.
|
||||||
|
pub fn err(
|
||||||
|
comptime format: []const u8,
|
||||||
|
args: anytype,
|
||||||
|
) void {
|
||||||
|
if (!logs_off and @intFromEnum(std.log.Level.err) <= @intFromEnum(log_level))
|
||||||
|
scoped_log.err(format, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Log a warning message. This log level is intended to be used if
|
||||||
|
/// it is uncertain whether something has gone wrong or not, but the
|
||||||
|
/// circumstances would be worth investigating.
|
||||||
|
pub fn warn(
|
||||||
|
comptime format: []const u8,
|
||||||
|
args: anytype,
|
||||||
|
) void {
|
||||||
|
if (!logs_off and @intFromEnum(std.log.Level.warn) <= @intFromEnum(log_level))
|
||||||
|
scoped_log.warn(format, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Log an info message. This log level is intended to be used for
|
||||||
|
/// general messages about the state of the program.
|
||||||
|
pub fn info(
|
||||||
|
comptime format: []const u8,
|
||||||
|
args: anytype,
|
||||||
|
) void {
|
||||||
|
if (!logs_off and @intFromEnum(std.log.Level.info) <= @intFromEnum(log_level))
|
||||||
|
scoped_log.info(format, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Log a debug message. This log level is intended to be used for
|
||||||
|
/// messages which are only useful for debugging.
|
||||||
|
pub fn debug(
|
||||||
|
comptime format: []const u8,
|
||||||
|
args: anytype,
|
||||||
|
) void {
|
||||||
|
if (!logs_off and @intFromEnum(std.log.Level.debug) <= @intFromEnum(log_level))
|
||||||
|
scoped_log.debug(format, args);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
pub const Options = struct {
|
pub const Options = struct {
|
||||||
region: []const u8 = "aws-global",
|
region: []const u8 = "aws-global",
|
||||||
|
@ -126,12 +188,15 @@ pub fn Request(comptime request_action: anytype) type {
|
||||||
log.debug("Rest method: '{s}'", .{aws_request.method});
|
log.debug("Rest method: '{s}'", .{aws_request.method});
|
||||||
log.debug("Rest success code: '{d}'", .{Action.http_config.success_code});
|
log.debug("Rest success code: '{d}'", .{Action.http_config.success_code});
|
||||||
log.debug("Rest raw uri: '{s}'", .{Action.http_config.uri});
|
log.debug("Rest raw uri: '{s}'", .{Action.http_config.uri});
|
||||||
|
var al = std.ArrayList([]const u8).init(options.client.allocator);
|
||||||
|
defer al.deinit();
|
||||||
aws_request.path = try buildPath(
|
aws_request.path = try buildPath(
|
||||||
options.client.allocator,
|
options.client.allocator,
|
||||||
Action.http_config.uri,
|
Action.http_config.uri,
|
||||||
ActionRequest,
|
ActionRequest,
|
||||||
request,
|
request,
|
||||||
!std.mem.eql(u8, Self.service_meta.sdk_id, "S3"),
|
!std.mem.eql(u8, Self.service_meta.sdk_id, "S3"),
|
||||||
|
&al,
|
||||||
);
|
);
|
||||||
defer options.client.allocator.free(aws_request.path);
|
defer options.client.allocator.free(aws_request.path);
|
||||||
log.debug("Rest processed uri: '{s}'", .{aws_request.path});
|
log.debug("Rest processed uri: '{s}'", .{aws_request.path});
|
||||||
|
@ -163,7 +228,7 @@ pub fn Request(comptime request_action: anytype) type {
|
||||||
defer nameAllocator.deinit();
|
defer nameAllocator.deinit();
|
||||||
if (Self.service_meta.aws_protocol == .rest_json_1) {
|
if (Self.service_meta.aws_protocol == .rest_json_1) {
|
||||||
if (std.mem.eql(u8, "PUT", aws_request.method) or std.mem.eql(u8, "POST", aws_request.method)) {
|
if (std.mem.eql(u8, "PUT", aws_request.method) or std.mem.eql(u8, "POST", aws_request.method)) {
|
||||||
try json.stringify(request, .{ .whitespace = .{} }, buffer.writer());
|
try json.stringify(request, .{ .whitespace = .{}, .emit_null = false, .exclude_fields = al.items }, buffer.writer());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
aws_request.body = buffer.items;
|
aws_request.body = buffer.items;
|
||||||
|
@ -944,6 +1009,7 @@ fn buildPath(
|
||||||
comptime ActionRequest: type,
|
comptime ActionRequest: type,
|
||||||
request: anytype,
|
request: anytype,
|
||||||
encode_slash: bool,
|
encode_slash: bool,
|
||||||
|
replaced_fields: *std.ArrayList([]const u8),
|
||||||
) ![]const u8 {
|
) ![]const u8 {
|
||||||
var buffer = try std.ArrayList(u8).initCapacity(allocator, raw_uri.len);
|
var buffer = try std.ArrayList(u8).initCapacity(allocator, raw_uri.len);
|
||||||
// const writer = buffer.writer();
|
// const writer = buffer.writer();
|
||||||
|
@ -965,6 +1031,7 @@ fn buildPath(
|
||||||
const replacement_label = raw_uri[start..end];
|
const replacement_label = raw_uri[start..end];
|
||||||
inline for (std.meta.fields(ActionRequest)) |field| {
|
inline for (std.meta.fields(ActionRequest)) |field| {
|
||||||
if (std.mem.eql(u8, request.fieldNameFor(field.name), replacement_label)) {
|
if (std.mem.eql(u8, request.fieldNameFor(field.name), replacement_label)) {
|
||||||
|
try replaced_fields.append(replacement_label);
|
||||||
var replacement_buffer = try std.ArrayList(u8).initCapacity(allocator, raw_uri.len);
|
var replacement_buffer = try std.ArrayList(u8).initCapacity(allocator, raw_uri.len);
|
||||||
defer replacement_buffer.deinit();
|
defer replacement_buffer.deinit();
|
||||||
var encoded_buffer = try std.ArrayList(u8).initCapacity(allocator, raw_uri.len);
|
var encoded_buffer = try std.ArrayList(u8).initCapacity(allocator, raw_uri.len);
|
||||||
|
@ -1254,23 +1321,27 @@ test "REST Json v1 serializes lists in queries" {
|
||||||
}
|
}
|
||||||
test "REST Json v1 buildpath substitutes" {
|
test "REST Json v1 buildpath substitutes" {
|
||||||
const allocator = std.testing.allocator;
|
const allocator = std.testing.allocator;
|
||||||
|
var al = std.ArrayList([]const u8).init(allocator);
|
||||||
|
defer al.deinit();
|
||||||
const svs = Services(.{.lambda}){};
|
const svs = Services(.{.lambda}){};
|
||||||
const request = svs.lambda.list_functions.Request{
|
const request = svs.lambda.list_functions.Request{
|
||||||
.max_items = 1,
|
.max_items = 1,
|
||||||
};
|
};
|
||||||
const input_path = "https://myhost/{MaxItems}/";
|
const input_path = "https://myhost/{MaxItems}/";
|
||||||
const output_path = try buildPath(allocator, input_path, @TypeOf(request), request, true);
|
const output_path = try buildPath(allocator, input_path, @TypeOf(request), request, true, &al);
|
||||||
defer allocator.free(output_path);
|
defer allocator.free(output_path);
|
||||||
try std.testing.expectEqualStrings("https://myhost/1/", output_path);
|
try std.testing.expectEqualStrings("https://myhost/1/", output_path);
|
||||||
}
|
}
|
||||||
test "REST Json v1 buildpath handles restricted characters" {
|
test "REST Json v1 buildpath handles restricted characters" {
|
||||||
const allocator = std.testing.allocator;
|
const allocator = std.testing.allocator;
|
||||||
|
var al = std.ArrayList([]const u8).init(allocator);
|
||||||
|
defer al.deinit();
|
||||||
const svs = Services(.{.lambda}){};
|
const svs = Services(.{.lambda}){};
|
||||||
const request = svs.lambda.list_functions.Request{
|
const request = svs.lambda.list_functions.Request{
|
||||||
.marker = ":",
|
.marker = ":",
|
||||||
};
|
};
|
||||||
const input_path = "https://myhost/{Marker}/";
|
const input_path = "https://myhost/{Marker}/";
|
||||||
const output_path = try buildPath(allocator, input_path, @TypeOf(request), request, true);
|
const output_path = try buildPath(allocator, input_path, @TypeOf(request), request, true, &al);
|
||||||
defer allocator.free(output_path);
|
defer allocator.free(output_path);
|
||||||
try std.testing.expectEqualStrings("https://myhost/%3A/", output_path);
|
try std.testing.expectEqualStrings("https://myhost/%3A/", output_path);
|
||||||
}
|
}
|
||||||
|
@ -1970,7 +2041,6 @@ test "rest_json_1_work_with_lambda: lambda tagResource (only), to excercise zig
|
||||||
try std.testing.expectEqual(std.http.Method.POST, test_harness.request_options.request_method);
|
try std.testing.expectEqual(std.http.Method.POST, test_harness.request_options.request_method);
|
||||||
try std.testing.expectEqualStrings(
|
try std.testing.expectEqualStrings(
|
||||||
\\{
|
\\{
|
||||||
\\ "Resource": "arn:aws:lambda:us-west-2:550620852718:function:awsome-lambda-LambdaStackawsomeLambda",
|
|
||||||
\\ "Tags": {
|
\\ "Tags": {
|
||||||
\\ "Foo": "Bar"
|
\\ "Foo": "Bar"
|
||||||
\\ }
|
\\ }
|
||||||
|
@ -1981,6 +2051,45 @@ test "rest_json_1_work_with_lambda: lambda tagResource (only), to excercise zig
|
||||||
// Response expectations
|
// Response expectations
|
||||||
try std.testing.expectEqualStrings("a521e152-6e32-4e67-9fb3-abc94e34551b", call.response_metadata.request_id);
|
try std.testing.expectEqualStrings("a521e152-6e32-4e67-9fb3-abc94e34551b", call.response_metadata.request_id);
|
||||||
}
|
}
|
||||||
|
test "rest_json_1_url_parameters_not_in_request: lambda update_function_code" {
|
||||||
|
const allocator = std.testing.allocator;
|
||||||
|
var test_harness = TestSetup.init(.{
|
||||||
|
.allocator = allocator,
|
||||||
|
.server_response = "{\"CodeSize\": 42}",
|
||||||
|
.server_response_status = .ok,
|
||||||
|
.server_response_headers = &.{
|
||||||
|
.{ .name = "Content-Type", .value = "application/json" },
|
||||||
|
.{ .name = "x-amzn-RequestId", .value = "a521e152-6e32-4e67-9fb3-abc94e34551b" },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
defer test_harness.deinit();
|
||||||
|
const options = try test_harness.start();
|
||||||
|
const lambda = (Services(.{.lambda}){}).lambda;
|
||||||
|
const architectures = [_][]const u8{"x86_64"};
|
||||||
|
const arches: [][]const u8 = @constCast(architectures[0..]);
|
||||||
|
const req = services.lambda.update_function_code.Request{
|
||||||
|
.function_name = "functionname",
|
||||||
|
.architectures = arches,
|
||||||
|
.zip_file = "zipfile",
|
||||||
|
};
|
||||||
|
const call = try Request(lambda.update_function_code).call(req, options);
|
||||||
|
defer call.deinit();
|
||||||
|
test_harness.stop();
|
||||||
|
// Request expectations
|
||||||
|
try std.testing.expectEqual(std.http.Method.PUT, test_harness.request_options.request_method);
|
||||||
|
try std.testing.expectEqualStrings(
|
||||||
|
\\{
|
||||||
|
\\ "ZipFile": "zipfile",
|
||||||
|
\\ "Architectures": [
|
||||||
|
\\ "x86_64"
|
||||||
|
\\ ]
|
||||||
|
\\}
|
||||||
|
, test_harness.request_options.request_body);
|
||||||
|
// Due to 17015, we see %253A instead of %3A
|
||||||
|
try std.testing.expectEqualStrings("/2015-03-31/functions/functionname/code", test_harness.request_options.request_target);
|
||||||
|
// Response expectations
|
||||||
|
try std.testing.expectEqualStrings("a521e152-6e32-4e67-9fb3-abc94e34551b", call.response_metadata.request_id);
|
||||||
|
}
|
||||||
test "ec2_query_no_input: EC2 describe regions" {
|
test "ec2_query_no_input: EC2 describe regions" {
|
||||||
const allocator = std.testing.allocator;
|
const allocator = std.testing.allocator;
|
||||||
var test_harness = TestSetup.init(.{
|
var test_harness = TestSetup.init(.{
|
||||||
|
|
|
@ -17,7 +17,57 @@ const CN_NORTHWEST_1_HASH = std.hash_map.hashString("cn-northwest-1");
|
||||||
const US_ISO_EAST_1_HASH = std.hash_map.hashString("us-iso-east-1");
|
const US_ISO_EAST_1_HASH = std.hash_map.hashString("us-iso-east-1");
|
||||||
const US_ISOB_EAST_1_HASH = std.hash_map.hashString("us-isob-east-1");
|
const US_ISOB_EAST_1_HASH = std.hash_map.hashString("us-isob-east-1");
|
||||||
|
|
||||||
const log = std.log.scoped(.awshttp);
|
const scoped_log = std.log.scoped(.awshttp);
|
||||||
|
|
||||||
|
/// Specifies logging level. This should not be touched unless the normal
|
||||||
|
/// zig logging capabilities are inaccessible (e.g. during a build)
|
||||||
|
pub var log_level: std.log.Level = .debug;
|
||||||
|
|
||||||
|
/// Turn off logging completely
|
||||||
|
pub var logs_off: bool = false;
|
||||||
|
const log = struct {
|
||||||
|
/// Log an error message. This log level is intended to be used
|
||||||
|
/// when something has gone wrong. This might be recoverable or might
|
||||||
|
/// be followed by the program exiting.
|
||||||
|
pub fn err(
|
||||||
|
comptime format: []const u8,
|
||||||
|
args: anytype,
|
||||||
|
) void {
|
||||||
|
if (!logs_off and @intFromEnum(std.log.Level.err) <= @intFromEnum(log_level))
|
||||||
|
scoped_log.err(format, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Log a warning message. This log level is intended to be used if
|
||||||
|
/// it is uncertain whether something has gone wrong or not, but the
|
||||||
|
/// circumstances would be worth investigating.
|
||||||
|
pub fn warn(
|
||||||
|
comptime format: []const u8,
|
||||||
|
args: anytype,
|
||||||
|
) void {
|
||||||
|
if (!logs_off and @intFromEnum(std.log.Level.warn) <= @intFromEnum(log_level))
|
||||||
|
scoped_log.warn(format, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Log an info message. This log level is intended to be used for
|
||||||
|
/// general messages about the state of the program.
|
||||||
|
pub fn info(
|
||||||
|
comptime format: []const u8,
|
||||||
|
args: anytype,
|
||||||
|
) void {
|
||||||
|
if (!logs_off and @intFromEnum(std.log.Level.info) <= @intFromEnum(log_level))
|
||||||
|
scoped_log.info(format, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Log a debug message. This log level is intended to be used for
|
||||||
|
/// messages which are only useful for debugging.
|
||||||
|
pub fn debug(
|
||||||
|
comptime format: []const u8,
|
||||||
|
args: anytype,
|
||||||
|
) void {
|
||||||
|
if (!logs_off and @intFromEnum(std.log.Level.debug) <= @intFromEnum(log_level))
|
||||||
|
scoped_log.debug(format, args);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
pub const AwsError = error{
|
pub const AwsError = error{
|
||||||
AddHeaderError,
|
AddHeaderError,
|
||||||
|
|
|
@ -22,7 +22,7 @@ pub const Result = struct {
|
||||||
self.allocator.free(h.value);
|
self.allocator.free(h.value);
|
||||||
}
|
}
|
||||||
self.allocator.free(self.headers);
|
self.allocator.free(self.headers);
|
||||||
log.debug("http result deinit complete", .{});
|
//log.debug("http result deinit complete", .{});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -3,8 +3,57 @@ const base = @import("aws_http_base.zig");
|
||||||
const auth = @import("aws_authentication.zig");
|
const auth = @import("aws_authentication.zig");
|
||||||
const date = @import("date.zig");
|
const date = @import("date.zig");
|
||||||
|
|
||||||
const log = std.log.scoped(.aws_signing);
|
const scoped_log = std.log.scoped(.aws_signing);
|
||||||
|
|
||||||
|
/// Specifies logging level. This should not be touched unless the normal
|
||||||
|
/// zig logging capabilities are inaccessible (e.g. during a build)
|
||||||
|
pub var log_level: std.log.Level = .debug;
|
||||||
|
|
||||||
|
/// Turn off logging completely
|
||||||
|
pub var logs_off: bool = false;
|
||||||
|
const log = struct {
|
||||||
|
/// Log an error message. This log level is intended to be used
|
||||||
|
/// when something has gone wrong. This might be recoverable or might
|
||||||
|
/// be followed by the program exiting.
|
||||||
|
pub fn err(
|
||||||
|
comptime format: []const u8,
|
||||||
|
args: anytype,
|
||||||
|
) void {
|
||||||
|
if (!logs_off and @intFromEnum(std.log.Level.err) <= @intFromEnum(log_level))
|
||||||
|
scoped_log.err(format, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Log a warning message. This log level is intended to be used if
|
||||||
|
/// it is uncertain whether something has gone wrong or not, but the
|
||||||
|
/// circumstances would be worth investigating.
|
||||||
|
pub fn warn(
|
||||||
|
comptime format: []const u8,
|
||||||
|
args: anytype,
|
||||||
|
) void {
|
||||||
|
if (!logs_off and @intFromEnum(std.log.Level.warn) <= @intFromEnum(log_level))
|
||||||
|
scoped_log.warn(format, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Log an info message. This log level is intended to be used for
|
||||||
|
/// general messages about the state of the program.
|
||||||
|
pub fn info(
|
||||||
|
comptime format: []const u8,
|
||||||
|
args: anytype,
|
||||||
|
) void {
|
||||||
|
if (!logs_off and @intFromEnum(std.log.Level.info) <= @intFromEnum(log_level))
|
||||||
|
scoped_log.info(format, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Log a debug message. This log level is intended to be used for
|
||||||
|
/// messages which are only useful for debugging.
|
||||||
|
pub fn debug(
|
||||||
|
comptime format: []const u8,
|
||||||
|
args: anytype,
|
||||||
|
) void {
|
||||||
|
if (!logs_off and @intFromEnum(std.log.Level.debug) <= @intFromEnum(log_level))
|
||||||
|
scoped_log.debug(format, args);
|
||||||
|
}
|
||||||
|
};
|
||||||
// TODO: Remove this?! This is an aws_signing, so we should know a thing
|
// TODO: Remove this?! This is an aws_signing, so we should know a thing
|
||||||
// or two about aws. So perhaps the right level of abstraction here
|
// or two about aws. So perhaps the right level of abstraction here
|
||||||
// is to have our service signing idiosyncracies dealt with in this
|
// is to have our service signing idiosyncracies dealt with in this
|
||||||
|
|
68
src/json.zig
68
src/json.zig
|
@ -2756,6 +2756,10 @@ pub const StringifyOptions = struct {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
emit_null: bool = true,
|
||||||
|
|
||||||
|
exclude_fields: ?[][]const u8 = null,
|
||||||
|
|
||||||
/// Controls the whitespace emitted
|
/// Controls the whitespace emitted
|
||||||
whitespace: ?Whitespace = null,
|
whitespace: ?Whitespace = null,
|
||||||
|
|
||||||
|
@ -2855,7 +2859,7 @@ pub fn stringify(
|
||||||
}
|
}
|
||||||
|
|
||||||
try out_stream.writeByte('{');
|
try out_stream.writeByte('{');
|
||||||
comptime var field_output = false;
|
var field_output = false;
|
||||||
var child_options = options;
|
var child_options = options;
|
||||||
if (child_options.whitespace) |*child_whitespace| {
|
if (child_options.whitespace) |*child_whitespace| {
|
||||||
child_whitespace.indent_level += 1;
|
child_whitespace.indent_level += 1;
|
||||||
|
@ -2864,34 +2868,46 @@ pub fn stringify(
|
||||||
// don't include void fields
|
// don't include void fields
|
||||||
if (Field.type == void) continue;
|
if (Field.type == void) continue;
|
||||||
|
|
||||||
if (!field_output) {
|
var output_this_field = true;
|
||||||
field_output = true;
|
if (!options.emit_null and @typeInfo(Field.type) == .Optional and @field(value, Field.name) == null) output_this_field = false;
|
||||||
} else {
|
|
||||||
try out_stream.writeByte(',');
|
|
||||||
}
|
|
||||||
if (child_options.whitespace) |child_whitespace| {
|
|
||||||
try out_stream.writeByte('\n');
|
|
||||||
try child_whitespace.outputIndent(out_stream);
|
|
||||||
}
|
|
||||||
var field_written = false;
|
|
||||||
if (comptime std.meta.hasFn(T, "jsonStringifyField"))
|
|
||||||
field_written = try value.jsonStringifyField(Field.name, child_options, out_stream);
|
|
||||||
|
|
||||||
if (!field_written) {
|
const final_name = if (comptime std.meta.hasFn(T, "fieldNameFor"))
|
||||||
if (comptime std.meta.hasFn(T, "fieldNameFor")) {
|
value.fieldNameFor(Field.name)
|
||||||
const name = value.fieldNameFor(Field.name);
|
else
|
||||||
try stringify(name, options, out_stream);
|
Field.name;
|
||||||
} else {
|
if (options.exclude_fields) |exclude_fields| {
|
||||||
try stringify(Field.name, options, out_stream);
|
for (exclude_fields) |exclude_field| {
|
||||||
}
|
if (std.mem.eql(u8, final_name, exclude_field)) {
|
||||||
|
output_this_field = false;
|
||||||
try out_stream.writeByte(':');
|
|
||||||
if (child_options.whitespace) |child_whitespace| {
|
|
||||||
if (child_whitespace.separator) {
|
|
||||||
try out_stream.writeByte(' ');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
try stringify(@field(value, Field.name), child_options, out_stream);
|
}
|
||||||
|
|
||||||
|
if (!field_output) {
|
||||||
|
field_output = output_this_field;
|
||||||
|
} else {
|
||||||
|
if (output_this_field) try out_stream.writeByte(',');
|
||||||
|
}
|
||||||
|
if (child_options.whitespace) |child_whitespace| {
|
||||||
|
if (output_this_field) try out_stream.writeByte('\n');
|
||||||
|
if (output_this_field) try child_whitespace.outputIndent(out_stream);
|
||||||
|
}
|
||||||
|
var field_written = false;
|
||||||
|
if (comptime std.meta.hasFn(T, "jsonStringifyField")) {
|
||||||
|
if (output_this_field) field_written = try value.jsonStringifyField(Field.name, child_options, out_stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!field_written) {
|
||||||
|
if (output_this_field) {
|
||||||
|
try stringify(final_name, options, out_stream);
|
||||||
|
try out_stream.writeByte(':');
|
||||||
|
}
|
||||||
|
if (child_options.whitespace) |child_whitespace| {
|
||||||
|
if (child_whitespace.separator) {
|
||||||
|
if (output_this_field) try out_stream.writeByte(' ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (output_this_field) try stringify(@field(value, Field.name), child_options, out_stream);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (field_output) {
|
if (field_output) {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user