srctree

Gregory Mullen parent 06f997e2 1e5e268d 9d15d5d3
Merge branch main into auth

examples/endpoint.zig added: 60, removed: 20, total 40
@@ -1,6 +1,20 @@
//! Quick start example using Verse Endpoints.
 
/// `Endpoints` here is a constructed type that will do some validation, and
/// statically and recursively construct the routes supplied.
const Endpoints = verse.Endpoints(.{
// Note index.zig sets `verse_name = .root;` which will cause the routes it
// lists to be flattened out. `/` will resolve to the function within
// `index.zig` with the name `index`.
@import("endpoint/index.zig"),
// The remaining endpoints (only random.zig here) are declared normally, and
// will use verse_name as the route name. The file name is not semantic,
// the routing will constructed only on the verse_name variable within the
// given type.
@import("endpoint/random.zig"),
// Endpoints don't have to be files, you can define a struct inline with the
// minimum verse variables and handler functions and Verse will include them
// as a route.
});
 
pub fn main() !void {
 
examples/endpoint/index.zig added: 60, removed: 20, total 40
@@ -8,8 +8,11 @@ pub const verse_routes = [_]Router.Match{
Router.ANY("hi", hi),
};
 
/// This is commented out here, as it's included within the root endpoint,
/// but because this endpoint will be flattened out into root directory;
/// declaring it here, or there are equivalent options.
pub const verse_endpoints = verse.Endpoints(.{
@import("random.zig"),
// @import("random.zig"),
});
 
pub fn index(frame: *Frame) !void {
 
src/endpoint.zig added: 60, removed: 20, total 40
@@ -25,7 +25,7 @@ pub fn Endpoints(endpoints: anytype) type {
pub const Self = @This();
pub const Endpoints = endpoints;
 
pub const routes = buildRoutes(endpoints[0]);
pub const routes = collectRoutes(endpoints);
 
pub fn init(a: Allocator) Self {
return .{
@@ -52,28 +52,51 @@ fn validateEndpoint(EP: anytype) void {
"Expected `pub const verse_name = .endpoint_name;` from: " ++ @typeName(EP));
}
 
fn routeCount(EP: type) usize {
fn routeCount(endpoints: anytype) usize {
var count: usize = 0;
for (@typeInfo(EP).Struct.decls) |decl| {
if (eql(u8, "index", decl.name)) count += 1;
}
 
if (@hasDecl(EP, "verse_routes")) for (EP.verse_routes) |route| {
if (route.name.len == 0) {
@compileError("route name omitted for: " ++ @typeName(EP) ++ ". To support a directory URI, define an index() instead");
for (endpoints, 0..) |ep, i| {
for (@typeInfo(ep).Struct.decls) |decl| {
if (eql(u8, "index", decl.name)) count += 1;
}
count += 1;
};
 
if (@hasDecl(EP, "verse_endpoints")) {
count += EP.verse_endpoints.Endpoints.len;
if (@hasDecl(ep, "verse_routes")) for (ep.verse_routes) |route| {
if (route.name.len == 0) {
@compileError("route name omitted for: " ++ @typeName(ep) ++ ". To support a directory URI, define an index() instead");
}
count += 1;
};
 
if (@hasDecl(ep, "verse_endpoints")) {
count += ep.verse_endpoints.Endpoints.len;
}
 
if (i == 0 and ep.verse_name == .root) {
return count + endpoints.len - 1;
}
}
 
return count;
}
 
fn buildRoutes(EP: anytype) [routeCount(EP)]Router.Match {
var match: [routeCount(EP)]Router.Match = undefined;
fn collectRoutes(EPS: anytype) [routeCount(EPS)]Router.Match {
var match: [routeCount(EPS)]Router.Match = undefined;
var idx: usize = 0;
for (EPS) |EP| {
// Only flatten when the endpoint name is root
if (EP.verse_name == .root) {
for (buildRoutes(EP)) |r| {
match[idx] = r;
idx += 1;
}
} else {
match[idx] = Router.ROUTE(@tagName(EP.verse_name), &buildRoutes(EP));
idx += 1;
}
}
return match;
}
 
fn buildRoutes(EP: type) [routeCount(.{EP})]Router.Match {
var match: [routeCount(.{EP})]Router.Match = undefined;
var idx: usize = 0;
for (@typeInfo(EP).Struct.decls) |decl| {
if (eql(u8, "index", decl.name)) {