Compare commits
4 Commits
e5f5f0e8cd
...
ad54596837
Author | SHA1 | Date | |
---|---|---|---|
ad54596837 | |||
7f8ddd3461 | |||
f9e6f92026 | |||
dff03429d9 |
|
@ -11,8 +11,16 @@ pub const Options = struct {
|
|||
dualstack: bool = false,
|
||||
};
|
||||
|
||||
/// Using this constant may blow up build times. Recommed using Services()
|
||||
/// function directly, e.g. const services = Services(.{.sts, .ec2, .s3, .ddb}){};
|
||||
pub const services = servicemodel.services;
|
||||
|
||||
/// Get a service model by importing specific services only. As an example:
|
||||
/// const services = Services(.{.sts, .ec2, .s3, .ddb}){};
|
||||
///
|
||||
/// This will give you a constant with service data for sts, ec2, s3 and ddb only
|
||||
pub const Services = servicemodel.Services;
|
||||
|
||||
pub const Aws = struct {
|
||||
allocator: *std.mem.Allocator,
|
||||
aws_http: awshttp.AwsHttp,
|
||||
|
|
|
@ -20,10 +20,31 @@ pub const Smithy = struct {
|
|||
pub fn deinit(self: Self) void {
|
||||
for (self.shapes) |s| {
|
||||
switch (s.shape) {
|
||||
.string, .byte, .short, .integer, .long, .float, .double, .bigInteger, .bigDecimal => |v| self.allocator.free(v.traits),
|
||||
.string,
|
||||
.byte,
|
||||
.short,
|
||||
.integer,
|
||||
.long,
|
||||
.float,
|
||||
.double,
|
||||
.bigInteger,
|
||||
.bigDecimal,
|
||||
.blob,
|
||||
.boolean,
|
||||
.timestamp,
|
||||
.document,
|
||||
.member,
|
||||
.resource,
|
||||
=> |v| self.allocator.free(v.traits),
|
||||
.structure => |v| {
|
||||
for (v.members) |m| self.allocator.free(m.traits);
|
||||
self.allocator.free(v.members);
|
||||
self.allocator.free(v.traits);
|
||||
},
|
||||
.uniontype => |v| {
|
||||
for (v.members) |m| self.allocator.free(m.traits);
|
||||
self.allocator.free(v.members);
|
||||
self.allocator.free(v.traits);
|
||||
},
|
||||
.service => |v| {
|
||||
self.allocator.free(v.traits);
|
||||
|
@ -33,7 +54,17 @@ pub const Smithy = struct {
|
|||
if (v.errors) |e| self.allocator.free(e);
|
||||
self.allocator.free(v.traits);
|
||||
},
|
||||
else => {},
|
||||
.list => |v| {
|
||||
self.allocator.free(v.traits);
|
||||
},
|
||||
.set => |v| {
|
||||
self.allocator.free(v.traits);
|
||||
},
|
||||
.map => |v| {
|
||||
self.allocator.free(v.key);
|
||||
self.allocator.free(v.value);
|
||||
self.allocator.free(v.traits);
|
||||
},
|
||||
}
|
||||
}
|
||||
self.allocator.free(self.shapes);
|
||||
|
@ -212,6 +243,7 @@ pub fn parse(allocator: *std.mem.Allocator, json_model: []const u8) !Smithy {
|
|||
// list must be deinitialized by caller
|
||||
fn shapes(allocator: *std.mem.Allocator, map: anytype) ![]ShapeInfo {
|
||||
var list = try std.ArrayList(ShapeInfo).initCapacity(allocator, map.count());
|
||||
defer list.deinit();
|
||||
var iterator = map.iterator();
|
||||
while (iterator.next()) |kv| {
|
||||
const id_info = try parseId(kv.key_ptr.*);
|
||||
|
@ -392,6 +424,7 @@ fn parseMembers(allocator: *std.mem.Allocator, shape: ?std.json.Value) SmithyPar
|
|||
|
||||
const map = shape.?.Object;
|
||||
var list = std.ArrayList(TypeMember).initCapacity(allocator, map.count()) catch return SmithyParseError.OutOfMemory;
|
||||
defer list.deinit();
|
||||
var iterator = map.iterator();
|
||||
while (iterator.next()) |kv| {
|
||||
try list.append(TypeMember{
|
||||
|
@ -406,6 +439,7 @@ fn parseMembers(allocator: *std.mem.Allocator, shape: ?std.json.Value) SmithyPar
|
|||
// ArrayList of std.Json.Value
|
||||
fn parseTargetList(allocator: *std.mem.Allocator, list: anytype) SmithyParseError![][]const u8 {
|
||||
var array_list = std.ArrayList([]const u8).initCapacity(allocator, list.items.len) catch return SmithyParseError.OutOfMemory;
|
||||
defer array_list.deinit();
|
||||
for (list.items) |i| {
|
||||
try array_list.append(i.Object.get("target").?.String);
|
||||
}
|
||||
|
@ -424,6 +458,7 @@ fn parseTraits(allocator: *std.mem.Allocator, shape: ?std.json.Value) SmithyPars
|
|||
|
||||
const map = shape.?.Object;
|
||||
var list = std.ArrayList(Trait).initCapacity(allocator, map.count()) catch return SmithyParseError.OutOfMemory;
|
||||
defer list.deinit();
|
||||
var iterator = map.iterator();
|
||||
while (iterator.next()) |kv| {
|
||||
if (try getTrait(kv.key_ptr.*, kv.value_ptr.*)) |t|
|
||||
|
@ -622,6 +657,8 @@ fn read_file_to_string(allocator: *std.mem.Allocator, file_name: []const u8, max
|
|||
return file.readToEndAlloc(allocator, max_bytes);
|
||||
}
|
||||
var test_data: ?[]const u8 = null;
|
||||
const intrinsic_type_count: usize = 5; // 5 intrinsic types are added to every model
|
||||
|
||||
fn getTestData(allocator: *std.mem.Allocator) []const u8 {
|
||||
if (test_data) |d| return d;
|
||||
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||
|
@ -660,13 +697,14 @@ test "parse string" {
|
|||
const allocator = &gpa.allocator;
|
||||
const model = try parse(allocator, test_string);
|
||||
defer model.deinit();
|
||||
expect(std.mem.eql(u8, model.version, "1.0"));
|
||||
std.testing.expectEqual(@as(usize, 1), model.shapes.len);
|
||||
std.testing.expectEqualStrings("com.amazonaws.sts#AWSSecurityTokenServiceV20110615", model.shapes[0].id);
|
||||
std.testing.expectEqualStrings("com.amazonaws.sts", model.shapes[0].namespace);
|
||||
std.testing.expectEqualStrings("AWSSecurityTokenServiceV20110615", model.shapes[0].name);
|
||||
std.testing.expect(model.shapes[0].member == null);
|
||||
std.testing.expectEqualStrings("2011-06-15", model.shapes[0].shape.service.version);
|
||||
try expect(std.mem.eql(u8, model.version, "1.0"));
|
||||
|
||||
try std.testing.expectEqual(intrinsic_type_count + 1, model.shapes.len);
|
||||
try std.testing.expectEqualStrings("com.amazonaws.sts#AWSSecurityTokenServiceV20110615", model.shapes[0].id);
|
||||
try std.testing.expectEqualStrings("com.amazonaws.sts", model.shapes[0].namespace);
|
||||
try std.testing.expectEqualStrings("AWSSecurityTokenServiceV20110615", model.shapes[0].name);
|
||||
try std.testing.expect(model.shapes[0].member == null);
|
||||
try std.testing.expectEqualStrings("2011-06-15", model.shapes[0].shape.service.version);
|
||||
}
|
||||
test "parse shape with member" {
|
||||
const test_string =
|
||||
|
@ -693,13 +731,13 @@ test "parse shape with member" {
|
|||
const allocator = &gpa.allocator;
|
||||
const model = try parse(allocator, test_string);
|
||||
defer model.deinit();
|
||||
expect(std.mem.eql(u8, model.version, "1.0"));
|
||||
std.testing.expectEqual(@as(usize, 1), model.shapes.len);
|
||||
std.testing.expectEqualStrings("com.amazonaws.sts#AWSSecurityTokenServiceV20110615$member", model.shapes[0].id);
|
||||
std.testing.expectEqualStrings("com.amazonaws.sts", model.shapes[0].namespace);
|
||||
std.testing.expectEqualStrings("AWSSecurityTokenServiceV20110615", model.shapes[0].name);
|
||||
std.testing.expectEqualStrings("2011-06-15", model.shapes[0].shape.service.version);
|
||||
std.testing.expectEqualStrings("member", model.shapes[0].member.?);
|
||||
try expect(std.mem.eql(u8, model.version, "1.0"));
|
||||
try std.testing.expectEqual(intrinsic_type_count + 1, model.shapes.len);
|
||||
try std.testing.expectEqualStrings("com.amazonaws.sts#AWSSecurityTokenServiceV20110615$member", model.shapes[0].id);
|
||||
try std.testing.expectEqualStrings("com.amazonaws.sts", model.shapes[0].namespace);
|
||||
try std.testing.expectEqualStrings("AWSSecurityTokenServiceV20110615", model.shapes[0].name);
|
||||
try std.testing.expectEqualStrings("2011-06-15", model.shapes[0].shape.service.version);
|
||||
try std.testing.expectEqualStrings("member", model.shapes[0].member.?);
|
||||
}
|
||||
test "parse file" {
|
||||
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||
|
@ -708,12 +746,12 @@ test "parse file" {
|
|||
const test_string = getTestData(allocator);
|
||||
const model = try parse(allocator, test_string);
|
||||
defer model.deinit();
|
||||
std.testing.expectEqualStrings(model.version, "1.0");
|
||||
try std.testing.expectEqualStrings(model.version, "1.0");
|
||||
// metadata expectations
|
||||
// try expect(std.mem.eql(u8, model.version, "version 1.0"));
|
||||
|
||||
// shape expectations
|
||||
std.testing.expectEqual(@as(usize, 81), model.shapes.len);
|
||||
try std.testing.expectEqual(intrinsic_type_count + 81, model.shapes.len);
|
||||
var optsvc: ?ShapeInfo = null;
|
||||
for (model.shapes) |shape| {
|
||||
if (std.mem.eql(u8, shape.id, "com.amazonaws.sts#AWSSecurityTokenServiceV20110615")) {
|
||||
|
@ -721,13 +759,13 @@ test "parse file" {
|
|||
break;
|
||||
}
|
||||
}
|
||||
std.testing.expect(optsvc != null);
|
||||
try std.testing.expect(optsvc != null);
|
||||
const svc = optsvc.?;
|
||||
std.testing.expectEqualStrings("com.amazonaws.sts#AWSSecurityTokenServiceV20110615", svc.id);
|
||||
std.testing.expectEqualStrings("com.amazonaws.sts", svc.namespace);
|
||||
std.testing.expectEqualStrings("AWSSecurityTokenServiceV20110615", svc.name);
|
||||
std.testing.expectEqualStrings("2011-06-15", svc.shape.service.version);
|
||||
try std.testing.expectEqualStrings("com.amazonaws.sts#AWSSecurityTokenServiceV20110615", svc.id);
|
||||
try std.testing.expectEqualStrings("com.amazonaws.sts", svc.namespace);
|
||||
try std.testing.expectEqualStrings("AWSSecurityTokenServiceV20110615", svc.name);
|
||||
try std.testing.expectEqualStrings("2011-06-15", svc.shape.service.version);
|
||||
// Should be 6, but we don't handle title or xml namespace
|
||||
std.testing.expectEqual(@as(usize, 4), svc.shape.service.traits.len);
|
||||
std.testing.expectEqual(@as(usize, 8), svc.shape.service.operations.len);
|
||||
try std.testing.expectEqual(@as(usize, 4), svc.shape.service.traits.len);
|
||||
try std.testing.expectEqual(@as(usize, 8), svc.shape.service.operations.len);
|
||||
}
|
||||
|
|
|
@ -45,7 +45,8 @@ pub fn main() anyerror!void {
|
|||
|
||||
var client = aws.Aws.init(allocator);
|
||||
defer client.deinit();
|
||||
const resp = try client.call(aws.services.sts.get_caller_identity.Request{}, options);
|
||||
const services = aws.Services(.{.sts}){};
|
||||
const resp = try client.call(services.sts.get_caller_identity.Request{}, options);
|
||||
// TODO: This is a bit wonky. Root cause is lack of declarations in
|
||||
// comptime-generated types
|
||||
defer resp.deinit();
|
||||
|
@ -56,7 +57,7 @@ pub fn main() anyerror!void {
|
|||
|
||||
var client2 = aws.Aws.init(allocator);
|
||||
defer client2.deinit();
|
||||
const resp2 = try client2.call(aws.services.sts.get_caller_identity.Request{}, options); // catch here and try alloc?
|
||||
const resp2 = try client2.call(services.sts.get_caller_identity.Request{}, options); // catch here and try alloc?
|
||||
defer resp2.deinit();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,23 +1,57 @@
|
|||
const std = @import("std");
|
||||
const expectEqualStrings = std.testing.expectEqualStrings;
|
||||
|
||||
// TODO: Make generic
|
||||
fn Services() type {
|
||||
pub fn Services(service_imports: anytype) type {
|
||||
// This service list can be imported from a master file of all services
|
||||
// provided by codegen
|
||||
const service_list = @import("codegen/service_manifest.zig").services;
|
||||
|
||||
// From here, the fields of our structure can be generated at comptime...
|
||||
var fields: [service_list.len]std.builtin.TypeInfo.StructField = undefined;
|
||||
var fields: [serviceCount(service_list, service_imports)]std.builtin.TypeInfo.StructField = undefined;
|
||||
|
||||
// This is run at comptime with multiple nested loops and a large (267 at
|
||||
// time of writing) number of services. 4 was chosen by trial and error,
|
||||
// but otherwise the branch count will be the product of field length,
|
||||
// service list length and the number of imports requested
|
||||
@setEvalBranchQuota(4 * fields.len * service_list.len * std.math.min(service_imports.len, 1));
|
||||
var inx = 0;
|
||||
for (fields) |*item, i| {
|
||||
const import = @field(@import("codegen/models/" ++ service_list[i].file_name), service_list[i].export_name);
|
||||
item.* = .{
|
||||
.name = service_list[i].name,
|
||||
.field_type = @TypeOf(import),
|
||||
.default_value = import,
|
||||
.is_comptime = false,
|
||||
.alignment = 0,
|
||||
};
|
||||
if (service_imports.len == 0) {
|
||||
const import = @field(@import("codegen/models/" ++ service_list[i].file_name), service_list[i].export_name);
|
||||
item.* = .{
|
||||
.name = service_list[i].name,
|
||||
.field_type = @TypeOf(import),
|
||||
.default_value = import,
|
||||
.is_comptime = false,
|
||||
.alignment = 0,
|
||||
};
|
||||
continue;
|
||||
}
|
||||
|
||||
var found = false;
|
||||
// we will loop through the big list and check each service
|
||||
// against the list of desired imports
|
||||
while (inx < service_list.len) {
|
||||
for (service_imports) |si| {
|
||||
if (std.mem.eql(u8, @tagName(si), service_list[inx].name)) {
|
||||
const import = @field(@import("codegen/models/" ++ service_list[inx].file_name), service_list[inx].export_name);
|
||||
item.* = .{
|
||||
.name = service_list[inx].name,
|
||||
.field_type = @TypeOf(import),
|
||||
.default_value = import,
|
||||
.is_comptime = false,
|
||||
.alignment = 0,
|
||||
};
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
inx = inx + 1; // service found or not in list - move to next service
|
||||
if (found) break;
|
||||
}
|
||||
if (!found)
|
||||
@compileError("imported service(s) not found");
|
||||
}
|
||||
|
||||
// finally, generate the type
|
||||
|
@ -30,21 +64,32 @@ fn Services() type {
|
|||
},
|
||||
});
|
||||
}
|
||||
// TODO: One constant to rule them all is a bit much. We can keep this
|
||||
// in the back pocket, but let's move to a factory style getService("blah");
|
||||
pub const services = Services(){};
|
||||
|
||||
fn serviceCount(service_list: anytype, desired_services: anytype) usize {
|
||||
if (desired_services.len == 0) return service_list.len;
|
||||
return desired_services.len;
|
||||
}
|
||||
|
||||
/// Using this constant may blow up build times. Recommed using Services()
|
||||
/// function directly, e.g. const services = Services(.{.sts, .ec2, .s3, .ddb}){};
|
||||
pub const services = Services(.{}){};
|
||||
|
||||
test "services includes sts" {
|
||||
expectEqualStrings("2011-06-15", services.sts.version);
|
||||
try expectEqualStrings("2011-06-15", services.sts.version);
|
||||
}
|
||||
test "sts includes get_caller_identity" {
|
||||
expectEqualStrings("GetCallerIdentity", services.sts.get_caller_identity.action_name);
|
||||
try expectEqualStrings("GetCallerIdentity", services.sts.get_caller_identity.action_name);
|
||||
}
|
||||
test "can get service and action name from request" {
|
||||
// get request object. This call doesn't have parameters
|
||||
const req = services.sts.get_caller_identity.Request{};
|
||||
// const metadata = @TypeOf(req).metaInfo();
|
||||
const metadata = req.metaInfo();
|
||||
expectEqualStrings("2011-06-15", metadata.service.version);
|
||||
try expectEqualStrings("2011-06-15", metadata.service.version);
|
||||
// expectEqualStrings("GetCallerIdentity", metadata.action.action_name);
|
||||
}
|
||||
test "can filter services" {
|
||||
const filtered_services = Services(.{ .sts, .waf_v2 }){};
|
||||
// const filtered_services = Services(.{.sts}){};
|
||||
try expectEqualStrings("2011-06-15", filtered_services.sts.version);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user