const std = @import("std"); const service_list = @import("models/service_manifest.zig"); const expectEqualStrings = std.testing.expectEqualStrings; pub fn Services(service_imports: anytype) type { if (service_imports.len == 0) return services; // From here, the fields of our structure can be generated at comptime... var fields: [serviceCount(service_imports)]std.builtin.TypeInfo.StructField = undefined; for (fields) |*item, i| { const import_field = @field(service_list, @tagName(service_imports[i])); item.* = .{ .name = @tagName(service_imports[i]), .field_type = @TypeOf(import_field), .default_value = import_field, .is_comptime = false, .alignment = 0, }; } // finally, generate the type return @Type(.{ .Struct = .{ .layout = .Auto, .fields = &fields, .decls = &[_]std.builtin.TypeInfo.Declaration{}, .is_tuple = false, }, }); } fn serviceCount(desired_services: anytype) usize { if (desired_services.len == 0) return @TypeOf(service_list).Struct.fields.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 = service_list; test "services includes sts" { try expectEqualStrings("2011-06-15", services.sts.version); } test "sts includes get_caller_identity" { 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 = req.metaInfo(); try expectEqualStrings("2011-06-15", metadata.service_metadata.version); } test "can filter services" { const filtered_services = Services(.{ .sts, .wafv2 }){}; try expectEqualStrings("2011-06-15", filtered_services.sts.version); }