Compare commits

..

13 commits

Author SHA1 Message Date
5541742db3
update README to reflect new zig
Some checks failed
AWS-Zig Build / build-zig-amd64-host (push) Failing after 1m10s
2025-08-22 11:47:02 -07:00
b865285b24
update codegen to 0.15.1 2025-08-22 11:23:26 -07:00
9ed9c9b447
update dependencies 2025-08-22 11:22:58 -07:00
20d7d5766b
begin 0.15.1 upgrade - CI and dev tooling 2025-08-22 11:22:24 -07:00
47d34153b7
move mise to dot file 2025-08-22 07:54:37 -07:00
545130f2c7
Merge branch 'zig-develop' 2025-08-22 07:52:44 -07:00
369818e31e
add zls to mise 2025-08-22 07:52:30 -07:00
393a034df5
Merge branch 'master' into zig-develop
All checks were successful
aws-zig nightly build / build-zig-nightly (push) Successful in 9m22s
2025-04-16 19:07:47 -07:00
2a61160ef8
Merge branch 'master' into zig-develop 2025-04-16 19:06:00 -07:00
1fcfa3003c
update package url for nightly after forgejo migration
All checks were successful
aws-zig nightly build / build-zig-nightly (push) Successful in 1m15s
2025-03-31 09:02:31 -07:00
6322c465d5
Merge branch 'master' into zig-develop 2025-03-25 09:32:51 -07:00
aac7b03c2e
Merge branch 'master' into zig-develop 2025-03-23 16:24:49 -07:00
69ffe49cc8
fix json serialization for null/empty maps 2025-03-21 12:42:08 -07:00
12 changed files with 163 additions and 133 deletions

View file

@ -18,11 +18,9 @@ jobs:
- name: Check out repository code
uses: actions/checkout@v4
- name: Setup Zig
uses: https://github.com/mlugg/setup-zig@v2.0.1
with:
version: 0.14.0
- name: Restore Zig caches
uses: https://github.com/Hanaasagi/zig-action-cache@3954aae427f8b05914e08dfd79f15e1f2e435929
uses: https://github.com/mlugg/setup-zig@v2.0.5
# We will let setup-zig use minimum_zig_version from build.zig.zon
# setup-zig also sets up the zig cache appropriately
- name: Ulimit
run: ulimit -a
- name: Run smoke test

View file

@ -29,8 +29,6 @@ jobs:
uses: https://github.com/mlugg/setup-zig@v2.0.1
with:
version: master
- name: Restore Zig caches
uses: https://github.com/Hanaasagi/zig-action-cache@3954aae427f8b05914e08dfd79f15e1f2e435929
- name: Run smoke test
run: zig build smoke-test --verbose
- name: Run full tests

View file

@ -3,7 +3,7 @@ on:
workflow_dispatch:
push:
branches:
- 'zig-0.13'
- 'zig-0.14.x'
env:
ACTIONS_RUNTIME_TOKEN: ${{ secrets.GITHUB_TOKEN }}
ACTIONS_RUNTIME_URL: ${{ env.GITHUB_SERVER_URL }}/api/actions_pipeline/
@ -18,13 +18,11 @@ jobs:
- name: Check out repository code
uses: actions/checkout@v4
with:
ref: zig-0.13
ref: zig-0.14.x
- name: Setup Zig
uses: https://github.com/mlugg/setup-zig@v2.0.1
with:
version: 0.13.0
- name: Restore Zig caches
uses: https://github.com/Hanaasagi/zig-action-cache@3954aae427f8b05914e08dfd79f15e1f2e435929
version: 0.14.0
- name: Run smoke test
run: zig build smoke-test --verbose
- name: Run full tests

View file

@ -1,4 +1,5 @@
[tools]
pre-commit = "latest"
"ubi:DonIsaac/zlint" = "latest"
zig = "0.14.1"
zig = "0.15.1"
zls = "0.14.0"

View file

@ -1,18 +1,17 @@
AWS SDK for Zig
===============
[Zig 0.14](https://ziglang.org/download/#release-0.14.0):
[Zig 0.15.1](https://ziglang.org/download/#release-0.15.1):
[![Build Status: Zig 0.14.0](https://git.lerch.org/lobo/aws-sdk-for-zig/actions/workflows/build.yaml/badge.svg)](https://git.lerch.org/lobo/aws-sdk-for-zig/actions?workflow=build.yaml&state=closed)
[![Build Status: Zig 0.15.1](https://git.lerch.org/lobo/aws-sdk-for-zig/actions/workflows/build.yaml/badge.svg)](https://git.lerch.org/lobo/aws-sdk-for-zig/actions?workflow=build.yaml&state=closed)
[Nightly Zig](https://ziglang.org/download/):
[![Build Status: Zig Nightly](https://git.lerch.org/lobo/aws-sdk-for-zig/actions/workflows/zig-nightly.yaml/badge.svg)](https://git.lerch.org/lobo/aws-sdk-for-zig/actions?workflow=zig-nightly.yaml&state=closed)
[Zig 0.13](https://ziglang.org/download/#release-0.13.0):
[![Build Status: Zig 0.13.0](https://git.lerch.org/lobo/aws-sdk-for-zig/actions/workflows/zig-previous.yaml/badge.svg)](https://git.lerch.org/lobo/aws-sdk-for-zig/actions?workflow=zig-previous.yaml&state=closed)
[Zig 0.14.1](https://ziglang.org/download/#release-0.14.1):
[![Build Status: Zig 0.14.x](https://git.lerch.org/lobo/aws-sdk-for-zig/actions/workflows/zig-previous.yaml/badge.svg)](https://git.lerch.org/lobo/aws-sdk-for-zig/actions?workflow=zig-previous.yaml&state=closed)
Current executable size for the demo is 980k after compiling with -Doptimize=ReleaseSmall
in x86_64-linux, and will vary based on services used. Tested targets:
@ -30,15 +29,15 @@ Tested targets are built, but not continuously tested, by CI.
Branches
--------
* **master**: This branch tracks the latest released zig version
* **zig-0.13**: This branch tracks the 0.13 released zig version.
Support for the previous version is best effort, generally
degrading over time. Fixes will generally appear in master, then
backported into the previous version.
* **zig-develop**: This branch tracks zig nightly, and is used mainly as a canary
for breaking changes that will need to be dealt with when
a new zig release appears. Expect significant delays in any
build failures (PRs always welcome!).
* **master**: This branch tracks the latest released zig version
* **zig-0.14.x**: This branch tracks the 0.14/0.14.1 released zig versions.
Support for these previous version is best effort, generally
degrading over time. Fixes will generally appear in master, then
backported into the previous version.
Other branches/tags exist but are unsupported

View file

@ -11,19 +11,20 @@
"README.md",
"LICENSE",
},
.minimum_zig_version = "0.15.1",
.dependencies = .{
.smithy = .{
.url = "https://git.lerch.org/lobo/smithy/archive/fd9be1afbfcc60d52896c077d8e9c963bb667bf1.tar.gz",
.hash = "smithy-1.0.0-uAyBgZPSAgBHStx7nrj0u3sN66g8Ppnn3XFUEJhn00rP",
.url = "git+https://git.lerch.org/lobo/smithy.git#09c0a618877ebaf8e15fbfc505983876f4e063d5",
.hash = "smithy-1.0.0-uAyBgTnTAgBp2v6vypGcK5-YOCtxs2iEqR-4LfC5FTlS",
},
.models = .{
.url = "https://github.com/aws/aws-sdk-go-v2/archive/refs/tags/release-2025-05-05.tar.gz",
.hash = "N-V-__8AAKWdeiawujEcrfukQbb8lLAiQIRT0uG5gCcm4b7W",
},
.zeit = .{
.url = "git+https://github.com/rockorager/zeit#f86d568b89a5922f084dae524a1eaf709855cd5e",
.hash = "zeit-0.6.0-5I6bkzt5AgC1_BCuSzXkV0JHeF4Mhti1Z_jFC7E_nmD2",
.url = "git+https://github.com/rockorager/zeit?ref=zig-0.15#ed2ca60db118414bda2b12df2039e33bad3b0b88",
.hash = "zeit-0.6.0-5I6bk0J9AgCVa0nnyL0lNY9Xa9F68hHq-ZarhuXNV-Jb",
},
.date = .{
.path = "lib/date",
@ -32,8 +33,8 @@
.path = "lib/json",
},
.case = .{
.url = "git+https://github.com/travisstaloch/case.git#610caade88ca54d2745f115114b08e73e2c6fe02",
.hash = "N-V-__8AAIfIAAC_RzCtghVVBVdqUzB8AaaGIyvK2WWz38bC",
.url = "git+https://github.com/travisstaloch/case.git#f8003fe5f93b65f673d10d41323e347225e8cb87",
.hash = "case-0.0.1-chGYqx_EAADaGJjmoln5M1iMBDTrMdd8to5wdEVpfXm4",
},
},
}

View file

@ -1,11 +1,19 @@
.{
.name = "aws-zig-codegen",
.name = .codegen,
.version = "0.0.1",
.paths = .{
"build.zig",
"build.zig.zon",
"src",
"README.md",
"LICENSE",
},
.fingerprint = 0x41c2ec2d551fe279,
.dependencies = .{
.smithy = .{
.url = "https://git.lerch.org/lobo/smithy/archive/41b61745d25a65817209dd5dddbb5f9b66896a99.tar.gz",
.hash = "122087deb0ae309b2258d59b40d82fe5921fdfc35b420bb59033244851f7f276fa34",
.url = "git+https://git.lerch.org/lobo/smithy.git#09c0a618877ebaf8e15fbfc505983876f4e063d5",
.hash = "smithy-1.0.0-uAyBgTnTAgBp2v6vypGcK5-YOCtxs2iEqR-4LfC5FTlS",
},
},
}

View file

@ -12,7 +12,7 @@ allocator: std.mem.Allocator,
indent_level: u64,
pub fn appendToTypeStack(self: @This(), shape_info: *const smithy.ShapeInfo) !void {
try self.type_stack.append(shape_info);
try self.type_stack.append(self.allocator, shape_info);
}
pub fn popFromTypeStack(self: @This()) void {

View file

@ -107,8 +107,9 @@ pub fn computeDirectoryHash(
const arena = arena_instance.allocator();
// Collect all files, recursively, then sort.
var all_files = std.ArrayList(*HashedFile).init(gpa);
defer all_files.deinit();
// Normally we're looking at around 300 model files
var all_files = try std.ArrayList(*HashedFile).initCapacity(gpa, 300);
defer all_files.deinit(gpa);
var walker = try dir.walk(gpa);
defer walker.deinit();
@ -139,7 +140,7 @@ pub fn computeDirectoryHash(
wait_group.start();
try thread_pool.spawn(workerHashFile, .{ dir, hashed_file, &wait_group });
try all_files.append(hashed_file);
try all_files.append(gpa, hashed_file);
}
}
@ -155,7 +156,7 @@ pub fn computeDirectoryHash(
hasher.update(&hashed_file.hash);
}
if (any_failures) return error.DirectoryHashUnavailable;
if (options.needFileHashes) options.fileHashes = try all_files.toOwnedSlice();
if (options.needFileHashes) options.fileHashes = try all_files.toOwnedSlice(gpa);
return hasher.finalResult();
}
fn workerHashFile(dir: std.fs.Dir, hashed_file: *HashedFile, wg: *std.Thread.WaitGroup) void {

View file

@ -17,6 +17,9 @@ const ServiceShape = smt.ServiceShape;
const ListShape = smt.ListShape;
const MapShape = smt.MapShape;
// manifest file 21k currently, but unbounded
var manifest_buf: [1024 * 32]u8 = undefined;
pub fn main() anyerror!void {
const root_progress_node = std.Progress.start(.{});
defer root_progress_node.end();
@ -27,7 +30,8 @@ pub fn main() anyerror!void {
const args = try std.process.argsAlloc(allocator);
defer std.process.argsFree(allocator, args);
const stdout = std.io.getStdOut().writer();
var stdout_writer = std.fs.File.stdout().writer(&.{});
const stdout = &stdout_writer.interface;
var output_dir = std.fs.cwd();
defer if (output_dir.fd > 0) output_dir.close();
@ -48,11 +52,10 @@ pub fn main() anyerror!void {
models_dir = try std.fs.cwd().openDir(args[i + 1], .{ .iterate = true });
}
// TODO: We need a different way to handle this file...
const manifest_file_started = false;
var manifest_file: std.fs.File = undefined;
defer if (manifest_file_started) manifest_file.close();
var manifest: std.fs.File.Writer = undefined;
var manifest_file = try output_dir.createFile("service_manifest.zig", .{});
defer manifest_file.close();
var manifest = manifest_file.writer(&manifest_buf).interface;
defer manifest.flush() catch @panic("Could not flush service manifest");
var files_processed: usize = 0;
var skip_next = true;
for (args) |arg| {
@ -71,11 +74,7 @@ pub fn main() anyerror!void {
skip_next = true;
continue;
}
if (!manifest_file_started) {
manifest_file = try output_dir.createFile("service_manifest.zig", .{});
manifest = manifest_file.writer();
}
try processFile(arg, output_dir, manifest);
try processFile(arg, output_dir, &manifest);
files_processed += 1;
}
if (files_processed == 0) {
@ -94,7 +93,7 @@ pub fn main() anyerror!void {
}
if (args.len == 0)
_ = try generateServices(allocator, ";", std.io.getStdIn(), stdout);
_ = try generateServices(allocator, ";", std.fs.File.stdin(), stdout);
if (verbose) {
const output_path = try output_dir.realpathAlloc(allocator, ".");
@ -133,7 +132,7 @@ fn processDirectories(models_dir: std.fs.Dir, output_dir: std.fs.Dir, parent_pro
// Do this in a brain dead fashion from here, no optimization
const manifest_file = try output_dir.createFile("service_manifest.zig", .{});
defer manifest_file.close();
const manifest = manifest_file.writer();
var manifest = manifest_file.writer(&manifest_buf);
var mi = models_dir.iterate();
const generating_models_progress = parent_progress.start("generating models", count);
@ -141,18 +140,15 @@ fn processDirectories(models_dir: std.fs.Dir, output_dir: std.fs.Dir, parent_pro
while (try mi.next()) |e| {
if ((e.kind == .file or e.kind == .sym_link) and std.mem.endsWith(u8, e.name, ".json")) {
try processFile(e.name, output_dir, manifest);
try processFile(e.name, output_dir, &manifest.interface);
generating_models_progress.completeOne();
}
}
// re-calculate so we can store the manifest
model_digest = calculated_manifest.model_dir_hash_digest;
_, calculated_manifest = try calculateDigests(models_dir, output_dir, &thread_pool);
try output_dir.writeFile(.{ .sub_path = "output_manifest.json", .data = try std.json.stringifyAlloc(
allocator,
calculated_manifest,
.{ .whitespace = .indent_2 },
) });
const data = try std.fmt.allocPrint(allocator, "{f}", .{std.json.fmt(calculated_manifest, .{ .whitespace = .indent_2 })});
try output_dir.writeFile(.{ .sub_path = "output_manifest.json", .data = data });
}
var model_digest: ?[Hasher.hex_multihash_len]u8 = null;
@ -200,7 +196,7 @@ fn calculateDigests(models_dir: std.fs.Dir, output_dir: std.fs.Dir, thread_pool:
},
};
}
fn processFile(file_name: []const u8, output_dir: std.fs.Dir, manifest: anytype) !void {
fn processFile(file_name: []const u8, output_dir: std.fs.Dir, manifest: *std.Io.Writer) !void {
// It's probably best to create our own allocator here so we can deint at the end and
// toss all allocations related to the services in this file
// I can't guarantee we're not leaking something, and at the end of the
@ -209,11 +205,10 @@ fn processFile(file_name: []const u8, output_dir: std.fs.Dir, manifest: anytype)
defer arena.deinit();
const allocator = arena.allocator();
var output = try std.ArrayListUnmanaged(u8).initCapacity(allocator, 1024 * 1024 * 2);
defer output.deinit(allocator);
var output = try std.Io.Writer.Allocating.initCapacity(allocator, 1024 * 1024 * 2);
defer output.deinit();
var counting_writer = std.io.countingWriter(output.writer(allocator));
var writer = counting_writer.writer();
var writer = output.writer;
_ = try writer.write("const std = @import(\"std\");\n");
_ = try writer.write("const smithy = @import(\"smithy\");\n");
@ -226,7 +221,12 @@ fn processFile(file_name: []const u8, output_dir: std.fs.Dir, manifest: anytype)
if (verbose) std.log.info("Processing file: {s}", .{file_name});
const service_names = generateServicesForFilePath(allocator, ";", file_name, writer) catch |err| {
const service_names = generateServicesForFilePath(
allocator,
";",
file_name,
&writer,
) catch |err| {
std.log.err("Error processing file: {s}", .{file_name});
return err;
};
@ -249,7 +249,7 @@ fn processFile(file_name: []const u8, output_dir: std.fs.Dir, manifest: anytype)
output_file_name = new_output_file_name;
}
const unformatted: [:0]const u8 = try output.toOwnedSliceSentinel(allocator, 0);
const unformatted: [:0]const u8 = try output.toOwnedSliceSentinel(0);
const formatted = try zigFmt(allocator, unformatted);
// Dump our buffer out to disk
@ -266,14 +266,17 @@ fn zigFmt(allocator: std.mem.Allocator, buffer: [:0]const u8) ![]const u8 {
var tree = try std.zig.Ast.parse(allocator, buffer, .zig);
defer tree.deinit(allocator);
return try tree.render(allocator);
var aw = try std.Io.Writer.Allocating.initCapacity(allocator, buffer.len);
defer aw.deinit();
try tree.render(allocator, &aw.writer, .{});
return aw.toOwnedSlice();
}
fn generateServicesForFilePath(
allocator: std.mem.Allocator,
comptime terminator: []const u8,
path: []const u8,
writer: anytype,
writer: *std.Io.Writer,
) ![][]const u8 {
const file = try std.fs.cwd().openFile(path, .{});
defer file.close();
@ -288,28 +291,34 @@ fn addReference(id: []const u8, map: *std.StringHashMap(u64)) !void {
res.value_ptr.* = 1;
}
}
fn countAllReferences(shape_ids: [][]const u8, shapes: std.StringHashMap(smithy.ShapeInfo), shape_references: *std.StringHashMap(u64), stack: *std.ArrayList([]const u8)) anyerror!void {
fn countAllReferences(allocator: std.mem.Allocator, shape_ids: [][]const u8, shapes: std.StringHashMap(smithy.ShapeInfo), shape_references: *std.StringHashMap(u64), stack: *std.ArrayList([]const u8)) anyerror!void {
for (shape_ids) |id| {
const shape = shapes.get(id);
if (shape == null) {
std.log.err("Error - could not find shape with id {s}", .{id});
return error.ShapeNotFound;
}
try countReferences(shape.?, shapes, shape_references, stack);
try countReferences(allocator, shape.?, shapes, shape_references, stack);
}
}
fn countTypeMembersReferences(type_members: []smithy.TypeMember, shapes: std.StringHashMap(smithy.ShapeInfo), shape_references: *std.StringHashMap(u64), stack: *std.ArrayList([]const u8)) anyerror!void {
fn countTypeMembersReferences(allocator: std.mem.Allocator, type_members: []smithy.TypeMember, shapes: std.StringHashMap(smithy.ShapeInfo), shape_references: *std.StringHashMap(u64), stack: *std.ArrayList([]const u8)) anyerror!void {
for (type_members) |m| {
const target = shapes.get(m.target);
if (target == null) {
std.log.err("Error - could not find target {s}", .{m.target});
return error.TargetNotFound;
}
try countReferences(target.?, shapes, shape_references, stack);
try countReferences(allocator, target.?, shapes, shape_references, stack);
}
}
fn countReferences(shape: smithy.ShapeInfo, shapes: std.StringHashMap(smithy.ShapeInfo), shape_references: *std.StringHashMap(u64), stack: *std.ArrayList([]const u8)) anyerror!void {
fn countReferences(
allocator: std.mem.Allocator,
shape: smithy.ShapeInfo,
shapes: std.StringHashMap(smithy.ShapeInfo),
shape_references: *std.StringHashMap(u64),
stack: *std.ArrayList([]const u8),
) anyerror!void {
// Add ourselves as a reference, then we will continue down the tree
try addReference(shape.id, shape_references);
// Put ourselves on the stack. If we come back to ourselves, we want to end.
@ -317,7 +326,7 @@ fn countReferences(shape: smithy.ShapeInfo, shapes: std.StringHashMap(smithy.Sha
if (std.mem.eql(u8, shape.id, i))
return;
}
try stack.append(shape.id);
try stack.append(allocator, shape.id);
defer _ = stack.pop();
// Well, this is a fun read: https://awslabs.github.io/smithy/1.0/spec/core/model.html#recursive-shape-definitions
// Looks like recursion has special rules in the spec to accomodate Java.
@ -339,15 +348,15 @@ fn countReferences(shape: smithy.ShapeInfo, shapes: std.StringHashMap(smithy.Sha
.unit,
=> {},
.document, .member, .resource => {}, // less sure about these?
.list => |i| try countReferences(shapes.get(i.member_target).?, shapes, shape_references, stack),
.set => |i| try countReferences(shapes.get(i.member_target).?, shapes, shape_references, stack),
.list => |i| try countReferences(allocator, shapes.get(i.member_target).?, shapes, shape_references, stack),
.set => |i| try countReferences(allocator, shapes.get(i.member_target).?, shapes, shape_references, stack),
.map => |i| {
try countReferences(shapes.get(i.key).?, shapes, shape_references, stack);
try countReferences(shapes.get(i.value).?, shapes, shape_references, stack);
try countReferences(allocator, shapes.get(i.key).?, shapes, shape_references, stack);
try countReferences(allocator, shapes.get(i.value).?, shapes, shape_references, stack);
},
.structure => |m| try countTypeMembersReferences(m.members, shapes, shape_references, stack),
.uniontype => |m| try countTypeMembersReferences(m.members, shapes, shape_references, stack),
.service => |i| try countAllReferences(i.operations, shapes, shape_references, stack),
.structure => |m| try countTypeMembersReferences(allocator, m.members, shapes, shape_references, stack),
.uniontype => |m| try countTypeMembersReferences(allocator, m.members, shapes, shape_references, stack),
.service => |i| try countAllReferences(allocator, i.operations, shapes, shape_references, stack),
.operation => |op| {
if (op.input) |i| {
const val = shapes.get(i);
@ -355,7 +364,7 @@ fn countReferences(shape: smithy.ShapeInfo, shapes: std.StringHashMap(smithy.Sha
std.log.err("Error processing shape with id \"{s}\". Input shape \"{s}\" was not found", .{ shape.id, i });
return error.ShapeNotFound;
}
try countReferences(val.?, shapes, shape_references, stack);
try countReferences(allocator, val.?, shapes, shape_references, stack);
}
if (op.output) |i| {
const val = shapes.get(i);
@ -363,27 +372,31 @@ fn countReferences(shape: smithy.ShapeInfo, shapes: std.StringHashMap(smithy.Sha
std.log.err("Error processing shape with id \"{s}\". Output shape \"{s}\" was not found", .{ shape.id, i });
return error.ShapeNotFound;
}
try countReferences(val.?, shapes, shape_references, stack);
try countReferences(allocator, val.?, shapes, shape_references, stack);
}
if (op.errors) |i| try countAllReferences(i, shapes, shape_references, stack);
if (op.errors) |i| try countAllReferences(allocator, i, shapes, shape_references, stack);
},
.@"enum" => |m| try countTypeMembersReferences(m.members, shapes, shape_references, stack),
.@"enum" => |m| try countTypeMembersReferences(allocator, m.members, shapes, shape_references, stack),
}
}
fn generateServices(allocator: std.mem.Allocator, comptime _: []const u8, file: std.fs.File, writer: anytype) ![][]const u8 {
fn generateServices(
allocator: std.mem.Allocator,
comptime _: []const u8,
file: std.fs.File,
writer: *std.Io.Writer,
) ![][]const u8 {
const json = try file.readToEndAlloc(allocator, 1024 * 1024 * 1024);
defer allocator.free(json);
const model = try smithy.parse(allocator, json);
defer model.deinit();
var shapes = std.StringHashMap(smithy.ShapeInfo).init(allocator);
defer shapes.deinit();
var services = std.ArrayList(smithy.ShapeInfo).init(allocator);
defer services.deinit();
var services = try std.ArrayList(smithy.ShapeInfo).initCapacity(allocator, model.shapes.len);
for (model.shapes) |shape| {
try shapes.put(shape.id, shape);
switch (shape.shape) {
.service => try services.append(shape),
.service => services.appendAssumeCapacity(shape),
else => {},
}
}
@ -392,15 +405,15 @@ fn generateServices(allocator: std.mem.Allocator, comptime _: []const u8, file:
// a reference count in case there are recursive data structures
var shape_references = std.StringHashMap(u64).init(allocator);
defer shape_references.deinit();
var stack = std.ArrayList([]const u8).init(allocator);
defer stack.deinit();
var stack: std.ArrayList([]const u8) = .{};
defer stack.deinit(allocator);
for (services.items) |service|
try countReferences(service, shapes, &shape_references, &stack);
try countReferences(allocator, service, shapes, &shape_references, &stack);
var constant_names = std.ArrayList([]const u8).init(allocator);
defer constant_names.deinit();
var unresolved = std.ArrayList(smithy.ShapeInfo).init(allocator);
defer unresolved.deinit();
var constant_names = try std.ArrayList([]const u8).initCapacity(allocator, services.items.len);
defer constant_names.deinit(allocator);
var unresolved: std.ArrayList(smithy.ShapeInfo) = .{};
defer unresolved.deinit(allocator);
var generated = std.StringHashMap(void).init(allocator);
defer generated.deinit();
@ -445,7 +458,7 @@ fn generateServices(allocator: std.mem.Allocator, comptime _: []const u8, file:
// name of the field will be snake_case of whatever comes in from
// sdk_id. Not sure this will simple...
const constant_name = try support.constantName(allocator, sdk_id, .snake);
try constant_names.append(constant_name);
constant_names.appendAssumeCapacity(constant_name);
try writer.print("const Self = @This();\n", .{});
if (version) |v|
try writer.print("pub const version: ?[]const u8 = \"{s}\";\n", .{v})
@ -481,16 +494,16 @@ fn generateServices(allocator: std.mem.Allocator, comptime _: []const u8, file:
try generateOperation(allocator, shapes.get(op).?, state, writer);
}
try generateAdditionalTypes(allocator, state, writer);
return constant_names.toOwnedSlice();
return constant_names.toOwnedSlice(allocator);
}
fn generateAdditionalTypes(allocator: std.mem.Allocator, file_state: FileGenerationState, writer: anytype) !void {
fn generateAdditionalTypes(allocator: std.mem.Allocator, file_state: FileGenerationState, writer: *std.Io.Writer) !void {
// More types may be added during processing
while (file_state.additional_types_to_generate.pop()) |t| {
if (file_state.additional_types_generated.getEntry(t.name) != null) continue;
// std.log.info("\t\t{s}", .{t.name});
var type_stack = std.ArrayList(*const smithy.ShapeInfo).init(allocator);
defer type_stack.deinit();
var type_stack: std.ArrayList(*const smithy.ShapeInfo) = .{};
defer type_stack.deinit(allocator);
const state = GenerationState{
.type_stack = &type_stack,
.file_state = file_state,
@ -510,9 +523,9 @@ fn generateAdditionalTypes(allocator: std.mem.Allocator, file_state: FileGenerat
}
}
fn outputIndent(state: GenerationState, writer: anytype) !void {
fn outputIndent(state: GenerationState, writer: *std.Io.Writer) !void {
const n_chars = 4 * state.indent_level;
try writer.writeByteNTimes(' ', n_chars);
try writer.splatBytesAll(" ", n_chars);
}
const StructType = enum {
@ -536,12 +549,12 @@ const operation_sub_types = [_]OperationSubTypeInfo{
},
};
fn generateOperation(allocator: std.mem.Allocator, operation: smithy.ShapeInfo, file_state: FileGenerationState, writer: anytype) !void {
fn generateOperation(allocator: std.mem.Allocator, operation: smithy.ShapeInfo, file_state: FileGenerationState, writer: *std.Io.Writer) !void {
const snake_case_name = try support.constantName(allocator, operation.name, .snake);
defer allocator.free(snake_case_name);
var type_stack = std.ArrayList(*const smithy.ShapeInfo).init(allocator);
defer type_stack.deinit();
var type_stack: std.ArrayList(*const smithy.ShapeInfo) = .{};
defer type_stack.deinit(allocator);
const state = GenerationState{
.type_stack = &type_stack,
.file_state = file_state,
@ -586,7 +599,12 @@ fn generateOperation(allocator: std.mem.Allocator, operation: smithy.ShapeInfo,
new_state.indent_level = 0;
std.debug.assert(new_state.type_stack.items.len == 0);
try serialization.json.generateToJsonFunction(shape_id, writer.any(), new_state, generate_type_options.keyCase(.pascal));
try serialization.json.generateToJsonFunction(
shape_id,
writer,
new_state,
generate_type_options.keyCase(.pascal),
);
try writer.writeAll("\n");
},
@ -638,7 +656,7 @@ fn generateOperation(allocator: std.mem.Allocator, operation: smithy.ShapeInfo,
_ = try writer.write("} = .{};\n");
}
fn generateMetadataFunction(operation_name: []const u8, state: GenerationState, writer: anytype, options: GenerateTypeOptions) !void {
fn generateMetadataFunction(operation_name: []const u8, state: GenerationState, writer: *std.Io.Writer, options: GenerateTypeOptions) !void {
// TODO: Shove these lines in here, and also the else portion
// pub fn metaInfo(self: @This()) struct { service: @TypeOf(sts), action: @TypeOf(sts.get_caller_identity) } {
// return .{ .service = sts, .action = sts.get_caller_identity };
@ -699,7 +717,7 @@ fn getTypeName(allocator: std.mem.Allocator, shape: smithy.ShapeInfo) ![]const u
}
}
fn reuseCommonType(shape: smithy.ShapeInfo, writer: anytype, state: GenerationState) !bool {
fn reuseCommonType(shape: smithy.ShapeInfo, writer: *std.Io.Writer, state: GenerationState) !bool {
// We want to return if we're at the top level of the stack. There are three
// reasons for this:
// 1. For operations, we have a request that includes a metadata function
@ -729,14 +747,14 @@ fn reuseCommonType(shape: smithy.ShapeInfo, writer: anytype, state: GenerationSt
rc = true;
_ = try writer.write(type_name); // This can't possibly be this easy...
if (state.file_state.additional_types_generated.getEntry(shape.name) == null)
try state.file_state.additional_types_to_generate.append(shape);
try state.file_state.additional_types_to_generate.append(state.allocator, shape);
}
}
return rc;
}
/// return type is anyerror!void as this is a recursive function, so the compiler cannot properly infer error types
fn generateTypeFor(shape_id: []const u8, writer: anytype, state: GenerationState, comptime options: GenerateTypeOptions) anyerror!bool {
fn generateTypeFor(shape_id: []const u8, writer: *std.Io.Writer, state: GenerationState, comptime options: GenerateTypeOptions) anyerror!bool {
const end_structure = options.end_structure;
var rc = false;
@ -808,7 +826,8 @@ fn generateTypeFor(shape_id: []const u8, writer: anytype, state: GenerationState
.float => |s| try generateSimpleTypeFor(s, "f32", writer),
.long => |s| try generateSimpleTypeFor(s, "i64", writer),
.map => |m| {
if (!try reuseCommonType(shape_info, std.io.null_writer, state)) {
var null_writer = std.Io.Writer.Discarding.init(&.{}).writer;
if (!try reuseCommonType(shape_info, &null_writer, state)) {
try generateMapTypeFor(m, writer, state, options);
rc = true;
} else {
@ -825,7 +844,7 @@ fn generateTypeFor(shape_id: []const u8, writer: anytype, state: GenerationState
return rc;
}
fn generateMapTypeFor(map: anytype, writer: anytype, state: GenerationState, comptime options: GenerateTypeOptions) anyerror!void {
fn generateMapTypeFor(map: anytype, writer: *std.Io.Writer, state: GenerationState, comptime options: GenerateTypeOptions) anyerror!void {
_ = try writer.write("struct {\n");
try writer.writeAll("pub const is_map_type = true;\n\n");
@ -848,12 +867,12 @@ fn generateMapTypeFor(map: anytype, writer: anytype, state: GenerationState, com
_ = try writer.write("}");
}
fn generateSimpleTypeFor(_: anytype, type_name: []const u8, writer: anytype) !void {
fn generateSimpleTypeFor(_: anytype, type_name: []const u8, writer: *std.Io.Writer) !void {
_ = try writer.write(type_name); // This had required stuff but the problem was elsewhere. Better to leave as function just in case
}
const Mapping = struct { snake: []const u8, original: []const u8 };
fn generateComplexTypeFor(shape_id: []const u8, members: []smithy.TypeMember, type_type_name: []const u8, writer: anytype, state: GenerationState, comptime options: GenerateTypeOptions) anyerror!void {
fn generateComplexTypeFor(shape_id: []const u8, members: []smithy.TypeMember, type_type_name: []const u8, writer: *std.Io.Writer, state: GenerationState, comptime options: GenerateTypeOptions) anyerror!void {
_ = shape_id;
var arena = std.heap.ArenaAllocator.init(state.allocator);
@ -861,7 +880,7 @@ fn generateComplexTypeFor(shape_id: []const u8, members: []smithy.TypeMember, ty
const allocator = arena.allocator();
var field_name_mappings = try std.ArrayList(Mapping).initCapacity(allocator, members.len);
defer field_name_mappings.deinit();
defer field_name_mappings.deinit(allocator);
// There is an httpQueryParams trait as well, but nobody is using it. API GW
// pretends to, but it's an empty map
//
@ -869,13 +888,13 @@ fn generateComplexTypeFor(shape_id: []const u8, members: []smithy.TypeMember, ty
//
// httpLabel is interesting - right now we just assume anything can be used - do we need to track this?
var http_query_mappings = try std.ArrayList(Mapping).initCapacity(allocator, members.len);
defer http_query_mappings.deinit();
defer http_query_mappings.deinit(allocator);
var http_header_mappings = try std.ArrayList(Mapping).initCapacity(allocator, members.len);
defer http_header_mappings.deinit();
defer http_header_mappings.deinit(allocator);
var map_fields = std.ArrayList([]const u8).init(allocator);
defer map_fields.deinit();
var map_fields = try std.ArrayList([]const u8).initCapacity(allocator, members.len);
defer map_fields.deinit(allocator);
// prolog. We'll rely on caller to get the spacing correct here
_ = try writer.write(type_type_name);
@ -930,7 +949,7 @@ fn generateComplexTypeFor(shape_id: []const u8, members: []smithy.TypeMember, ty
try writer.print("{s}: ", .{member_name});
try writeOptional(member.traits, writer, null);
if (try generateTypeFor(member.target, writer, child_state, options.endStructure(true)))
try map_fields.append(try std.fmt.allocPrint(allocator, "{s}", .{member_name}));
map_fields.appendAssumeCapacity(try std.fmt.allocPrint(allocator, "{s}", .{member_name}));
if (!std.mem.eql(u8, "union", type_type_name))
try writeOptional(member.traits, writer, " = null");
@ -978,7 +997,14 @@ fn generateComplexTypeFor(shape_id: []const u8, members: []smithy.TypeMember, ty
_ = try writer.write("}\n");
}
fn writeMappings(state: GenerationState, @"pub": []const u8, mapping_name: []const u8, mappings: anytype, force_output: bool, writer: anytype) !void {
fn writeMappings(
state: GenerationState,
@"pub": []const u8,
mapping_name: []const u8,
mappings: anytype,
force_output: bool,
writer: *std.Io.Writer,
) !void {
if (mappings.items.len == 0 and !force_output) return;
try outputIndent(state, writer);
if (mappings.items.len == 0) {
@ -998,7 +1024,7 @@ fn writeMappings(state: GenerationState, @"pub": []const u8, mapping_name: []con
_ = try writer.write("};\n");
}
fn writeOptional(traits: ?[]smithy.Trait, writer: anytype, value: ?[]const u8) !void {
fn writeOptional(traits: ?[]smithy.Trait, writer: *std.Io.Writer, value: ?[]const u8) !void {
if (traits) |ts| if (smt.hasTrait(.required, ts)) return;
try writer.writeAll(value orelse "?");
}

View file

@ -17,7 +17,7 @@ const JsonMember = struct {
shape_info: smithy.ShapeInfo,
};
pub fn generateToJsonFunction(shape_id: []const u8, writer: std.io.AnyWriter, state: GenerationState, comptime options: GenerateTypeOptions) !void {
pub fn generateToJsonFunction(shape_id: []const u8, writer: *std.Io.Writer, state: GenerationState, comptime options: GenerateTypeOptions) !void {
_ = options;
const allocator = state.allocator;
@ -117,15 +117,15 @@ fn getMemberValueJson(allocator: std.mem.Allocator, source: []const u8, member:
const member_value = try std.fmt.allocPrint(allocator, "@field({s}, \"{s}\")", .{ source, member.field_name });
defer allocator.free(member_value);
var output_block = std.ArrayListUnmanaged(u8){};
const writer = output_block.writer(allocator);
var output_block = std.Io.Writer.Allocating.init(allocator);
defer output_block.deinit();
try writeMemberValue(
writer,
&output_block.writer,
member_value,
);
return output_block.toOwnedSlice(allocator);
return output_block.toOwnedSlice();
}
fn getShapeJsonValueType(shape: Shape) []const u8 {
@ -139,7 +139,7 @@ fn getShapeJsonValueType(shape: Shape) []const u8 {
}
fn writeMemberValue(
writer: anytype,
writer: *std.Io.Writer,
member_value: []const u8,
) !void {
try writer.writeAll(member_value);
@ -153,7 +153,7 @@ const WriteMemberJsonParams = struct {
member: smithy.TypeMember,
};
fn writeStructureJson(params: WriteMemberJsonParams, writer: std.io.AnyWriter) !void {
fn writeStructureJson(params: WriteMemberJsonParams, writer: *std.Io.Writer) !void {
const shape_type = "structure";
const allocator = params.state.allocator;
const state = params.state;
@ -221,7 +221,7 @@ fn writeStructureJson(params: WriteMemberJsonParams, writer: std.io.AnyWriter) !
}
}
fn writeListJson(list: smithy_tools.ListShape, params: WriteMemberJsonParams, writer: std.io.AnyWriter) anyerror!void {
fn writeListJson(list: smithy_tools.ListShape, params: WriteMemberJsonParams, writer: *std.Io.Writer) anyerror!void {
const state = params.state;
const allocator = state.allocator;
@ -274,7 +274,7 @@ fn writeListJson(list: smithy_tools.ListShape, params: WriteMemberJsonParams, wr
}
}
fn writeMapJson(map: smithy_tools.MapShape, params: WriteMemberJsonParams, writer: std.io.AnyWriter) anyerror!void {
fn writeMapJson(map: smithy_tools.MapShape, params: WriteMemberJsonParams, writer: *std.Io.Writer) anyerror!void {
const state = params.state;
const name = params.field_name;
const value = params.field_value;
@ -351,11 +351,11 @@ fn writeMapJson(map: smithy_tools.MapShape, params: WriteMemberJsonParams, write
}
}
fn writeScalarJson(comment: []const u8, params: WriteMemberJsonParams, writer: std.io.AnyWriter) anyerror!void {
fn writeScalarJson(comment: []const u8, params: WriteMemberJsonParams, writer: *std.Io.Writer) anyerror!void {
try writer.print("try jw.write({s}); // {s}\n\n", .{ params.field_value, comment });
}
fn writeMemberJson(params: WriteMemberJsonParams, writer: std.io.AnyWriter) anyerror!void {
fn writeMemberJson(params: WriteMemberJsonParams, writer: *std.Io.Writer) anyerror!void {
const shape_id = params.shape_id;
const state = params.state;
const shape_info = try smithy_tools.getShapeInfo(shape_id, state.file_state.shapes);

View file

@ -5,8 +5,8 @@
.minimum_zig_version = "0.14.0",
.dependencies = .{
.zeit = .{
.url = "git+https://github.com/rockorager/zeit#f86d568b89a5922f084dae524a1eaf709855cd5e",
.hash = "zeit-0.6.0-5I6bkzt5AgC1_BCuSzXkV0JHeF4Mhti1Z_jFC7E_nmD2",
.url = "git+https://github.com/rockorager/zeit?ref=zig-0.15#ed2ca60db118414bda2b12df2039e33bad3b0b88",
.hash = "zeit-0.6.0-5I6bk0J9AgCVa0nnyL0lNY9Xa9F68hHq-ZarhuXNV-Jb",
},
.json = .{
.path = "../json",