Skip to content

Commit

Permalink
implemented function to convert strings to int (#58)
Browse files Browse the repository at this point in the history
  • Loading branch information
ItsMeSamey authored and karlseguin committed Aug 8, 2024
1 parent df86de5 commit 69665a5
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 117 deletions.
73 changes: 25 additions & 48 deletions src/httpz.zig
Original file line number Diff line number Diff line change
Expand Up @@ -78,30 +78,7 @@ pub const ContentType = enum {
XML,
UNKNOWN,

const JS_BIT = @as(u16, @bitCast([2]u8{ 'j', 's' }));
const GZ_BIT = @as(u16, @bitCast([2]u8{ 'g', 'z' }));
const CSS_BIT = @as(u24, @bitCast([3]u8{ 'c', 's', 's' }));
const CSV_BIT = @as(u24, @bitCast([3]u8{ 'c', 's', 'v' }));
const EOT_BIT = @as(u24, @bitCast([3]u8{ 'e', 'o', 't' }));
const GIF_BIT = @as(u24, @bitCast([3]u8{ 'g', 'i', 'f' }));
const HTM_BIT = @as(u24, @bitCast([3]u8{ 'h', 't', 'm' }));
const ICO_BIT = @as(u24, @bitCast([3]u8{ 'i', 'c', 'o' }));
const JPG_BIT = @as(u24, @bitCast([3]u8{ 'j', 'p', 'g' }));
const OTF_BIT = @as(u24, @bitCast([3]u8{ 'o', 't', 'f' }));
const PDF_BIT = @as(u24, @bitCast([3]u8{ 'p', 'd', 'f' }));
const PNG_BIT = @as(u24, @bitCast([3]u8{ 'p', 'n', 'g' }));
const SVG_BIT = @as(u24, @bitCast([3]u8{ 's', 'v', 'g' }));
const TAR_BIT = @as(u24, @bitCast([3]u8{ 't', 'a', 'r' }));
const TTF_BIT = @as(u24, @bitCast([3]u8{ 't', 't', 'f' }));
const XML_BIT = @as(u24, @bitCast([3]u8{ 'x', 'm', 'l' }));
const JPEG_BIT = @as(u32, @bitCast([4]u8{ 'j', 'p', 'e', 'g' }));
const JSON_BIT = @as(u32, @bitCast([4]u8{ 'j', 's', 'o', 'n' }));
const HTML_BIT = @as(u32, @bitCast([4]u8{ 'h', 't', 'm', 'l' }));
const TEXT_BIT = @as(u32, @bitCast([4]u8{ 't', 'e', 'x', 't' }));
const WASM_BIT = @as(u32, @bitCast([4]u8{ 'w', 'a', 's', 'm' }));
const WOFF_BIT = @as(u32, @bitCast([4]u8{ 'w', 'o', 'f', 'f' }));
const WEBP_BIT = @as(u32, @bitCast([4]u8{ 'w', 'e', 'b', 'p' }));
const WOFF2_BIT = @as(u40, @bitCast([5]u8{ 'w', 'o', 'f', 'f', '2' }));
const asUint = @import("url.zig").asUint;

pub fn forExtension(ext: []const u8) ContentType {
if (ext.len == 0) return .UNKNOWN;
Expand All @@ -116,45 +93,45 @@ pub const ContentType = enum {
switch (temp.len) {
2 => {
switch (@as(u16, @bitCast(normalized[0..2].*))) {
JS_BIT => return .JS,
GZ_BIT => return .GZ,
asUint("js") => return .JS,
asUint("gz") => return .GZ,
else => return .UNKNOWN,
}
},
3 => {
switch (@as(u24, @bitCast(normalized[0..3].*))) {
CSS_BIT => return .CSS,
CSV_BIT => return .CSV,
EOT_BIT => return .EOT,
GIF_BIT => return .GIF,
HTM_BIT => return .HTML,
ICO_BIT => return .ICO,
JPG_BIT => return .JPG,
OTF_BIT => return .OTF,
PDF_BIT => return .PDF,
PNG_BIT => return .PNG,
SVG_BIT => return .SVG,
TAR_BIT => return .TAR,
TTF_BIT => return .TTF,
XML_BIT => return .XML,
asUint("css") => return .CSS,
asUint("csv") => return .CSV,
asUint("eot") => return .EOT,
asUint("gif") => return .GIF,
asUint("htm") => return .HTML,
asUint("ico") => return .ICO,
asUint("jpg") => return .JPG,
asUint("otf") => return .OTF,
asUint("pdf") => return .PDF,
asUint("png") => return .PNG,
asUint("svg") => return .SVG,
asUint("tar") => return .TAR,
asUint("ttf") => return .TTF,
asUint("xml") => return .XML,
else => return .UNKNOWN,
}
},
4 => {
switch (@as(u32, @bitCast(normalized[0..4].*))) {
JPEG_BIT => return .JPG,
JSON_BIT => return .JSON,
HTML_BIT => return .HTML,
TEXT_BIT => return .TEXT,
WASM_BIT => return .WASM,
WOFF_BIT => return .WOFF,
WEBP_BIT => return .WEBP,
asUint("jpeg") => return .JPG,
asUint("json") => return .JSON,
asUint("html") => return .HTML,
asUint("text") => return .TEXT,
asUint("wasm") => return .WASM,
asUint("woff") => return .WOFF,
asUint("webp") => return .WEBP,
else => return .UNKNOWN,
}
},
5 => {
switch (@as(u40, @bitCast(normalized[0..5].*))) {
WOFF2_BIT => return .WOFF2,
asUint("woff2") => return .WOFF2,
else => return .UNKNOWN,
}
},
Expand Down
41 changes: 15 additions & 26 deletions src/request.zig
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,6 @@ const Address = std.net.Address;
const Allocator = std.mem.Allocator;
const ArenaAllocator = std.heap.ArenaAllocator;

// this approach to matching method name comes from zhp
const GET_ = @as(u32, @bitCast([4]u8{ 'G', 'E', 'T', ' ' }));
const PUT_ = @as(u32, @bitCast([4]u8{ 'P', 'U', 'T', ' ' }));
const POST = @as(u32, @bitCast([4]u8{ 'P', 'O', 'S', 'T' }));
const HEAD = @as(u32, @bitCast([4]u8{ 'H', 'E', 'A', 'D' }));
const PATC = @as(u32, @bitCast([4]u8{ 'P', 'A', 'T', 'C' }));
const DELE = @as(u32, @bitCast([4]u8{ 'D', 'E', 'L', 'E' }));
const ETE_ = @as(u32, @bitCast([4]u8{ 'E', 'T', 'E', ' ' }));
const OPTI = @as(u32, @bitCast([4]u8{ 'O', 'P', 'T', 'I' }));
const ONS_ = @as(u32, @bitCast([4]u8{ 'O', 'N', 'S', ' ' }));
const HTTP = @as(u32, @bitCast([4]u8{ 'H', 'T', 'T', 'P' }));
const V1P0 = @as(u32, @bitCast([4]u8{ '/', '1', '.', '0' }));
const V1P1 = @as(u32, @bitCast([4]u8{ '/', '1', '.', '1' }));

pub const Request = struct {
// The URL of the request
url: Url,
Expand Down Expand Up @@ -531,6 +517,8 @@ pub const State = struct {

arena: *ArenaAllocator,

const asUint = @import("url.zig").asUint;

pub fn init(allocator: Allocator, arena: *ArenaAllocator, buffer_pool: *buffer.Pool, config: *const Config) !Request.State {
return .{
.pos = 0,
Expand Down Expand Up @@ -637,37 +625,38 @@ pub const State = struct {
// having to do any other bound-checking.
if (buf_len < 8) return false;

// this approach to matching method name comes from zhp
switch (@as(u32, @bitCast(buf[0..4].*))) {
GET_ => {
asUint("GET ") => {
self.pos = 4;
self.method = .GET;
},
PUT_ => {
asUint("PUT ") => {
self.pos = 4;
self.method = .PUT;
},
POST => {
asUint("POST") => {
if (buf[4] != ' ') return error.UnknownMethod;
self.pos = 5;
self.method = .POST;
},
HEAD => {
asUint("HEAD") => {
if (buf[4] != ' ') return error.UnknownMethod;
self.pos = 5;
self.method = .HEAD;
},
PATC => {
asUint("PATC") => {
if (buf[4] != 'H' or buf[5] != ' ') return error.UnknownMethod;
self.pos = 6;
self.method = .PATCH;
},
DELE => {
if (@as(u32, @bitCast(buf[3..7].*)) != ETE_) return error.UnknownMethod;
asUint("DELE") => {
if (@as(u32, @bitCast(buf[3..7].*)) != asUint("ETE ")) return error.UnknownMethod;
self.pos = 7;
self.method = .DELETE;
},
OPTI => {
if (@as(u32, @bitCast(buf[4..8].*)) != ONS_) return error.UnknownMethod;
asUint("OPTI") => {
if (@as(u32, @bitCast(buf[4..8].*)) != asUint("ONS ")) return error.UnknownMethod;
self.pos = 8;
self.method = .OPTIONS;
},
Expand Down Expand Up @@ -710,13 +699,13 @@ pub const State = struct {
const buf_len = buf.len;
if (buf_len < 10) return false;

if (@as(u32, @bitCast(buf[0..4].*)) != HTTP) {
if (@as(u32, @bitCast(buf[0..4].*)) != asUint("HTTP")) {
return error.UnknownProtocol;
}

self.protocol = switch (@as(u32, @bitCast(buf[4..8].*))) {
V1P1 => http.Protocol.HTTP11,
V1P0 => http.Protocol.HTTP10,
asUint("/1.1") => http.Protocol.HTTP11,
asUint("/1.0") => http.Protocol.HTTP10,
else => return error.UnsupportedProtocol,
};

Expand Down
97 changes: 54 additions & 43 deletions src/url.zig
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,6 @@ const metrics = @import("metrics.zig");

const Allocator = std.mem.Allocator;

const ENC_20 = @as(u16, @bitCast([2]u8{ '2', '0' }));
const ENC_21 = @as(u16, @bitCast([2]u8{ '2', '1' }));
const ENC_22 = @as(u16, @bitCast([2]u8{ '2', '2' }));
const ENC_23 = @as(u16, @bitCast([2]u8{ '2', '3' }));
const ENC_24 = @as(u16, @bitCast([2]u8{ '2', '4' }));
const ENC_25 = @as(u16, @bitCast([2]u8{ '2', '5' }));
const ENC_26 = @as(u16, @bitCast([2]u8{ '2', '6' }));
const ENC_27 = @as(u16, @bitCast([2]u8{ '2', '7' }));
const ENC_28 = @as(u16, @bitCast([2]u8{ '2', '8' }));
const ENC_29 = @as(u16, @bitCast([2]u8{ '2', '9' }));
const ENC_2A = @as(u16, @bitCast([2]u8{ '2', 'A' }));
const ENC_2B = @as(u16, @bitCast([2]u8{ '2', 'B' }));
const ENC_2C = @as(u16, @bitCast([2]u8{ '2', 'C' }));
const ENC_2F = @as(u16, @bitCast([2]u8{ '2', 'F' }));
const ENC_3A = @as(u16, @bitCast([2]u8{ '3', 'A' }));
const ENC_3B = @as(u16, @bitCast([2]u8{ '3', 'B' }));
const ENC_3D = @as(u16, @bitCast([2]u8{ '3', 'D' }));
const ENC_3F = @as(u16, @bitCast([2]u8{ '3', 'F' }));
const ENC_40 = @as(u16, @bitCast([2]u8{ '4', '0' }));
const ENC_5B = @as(u16, @bitCast([2]u8{ '5', 'B' }));
const ENC_5D = @as(u16, @bitCast([2]u8{ '5', 'D' }));

pub const Url = struct {
raw: []const u8 = "",
path: []const u8 = "",
Expand Down Expand Up @@ -109,27 +87,27 @@ pub const Url = struct {
if (b == '%') {
const enc = input[in_i + 1 .. in_i + 3];
out[i] = switch (@as(u16, @bitCast(enc[0..2].*))) {
ENC_20 => ' ',
ENC_21 => '!',
ENC_22 => '"',
ENC_23 => '#',
ENC_24 => '$',
ENC_25 => '%',
ENC_26 => '&',
ENC_27 => '\'',
ENC_28 => '(',
ENC_29 => ')',
ENC_2A => '*',
ENC_2B => '+',
ENC_2C => ',',
ENC_2F => '/',
ENC_3A => ':',
ENC_3B => ';',
ENC_3D => '=',
ENC_3F => '?',
ENC_40 => '@',
ENC_5B => '[',
ENC_5D => ']',
asUint("20") => ' ',
asUint("21") => '!',
asUint("22") => '"',
asUint("23") => '#',
asUint("24") => '$',
asUint("25") => '%',
asUint("26") => '&',
asUint("27") => '\'',
asUint("28") => '(',
asUint("29") => ')',
asUint("2A") => '*',
asUint("2B") => '+',
asUint("2C") => ',',
asUint("2F") => '/',
asUint("3A") => ':',
asUint("3B") => ';',
asUint("3D") => '=',
asUint("3F") => '?',
asUint("40") => '@',
asUint("5B") => '[',
asUint("5D") => ']',
else => HEX_DECODE[enc[0]] << 4 | HEX_DECODE[enc[1]],
};
in_i += 3;
Expand Down Expand Up @@ -174,6 +152,22 @@ pub const Url = struct {
}
};

/// converts ascii to unsigned int of appropriate size
pub fn asUint(comptime string: anytype) @Type(std.builtin.Type{
.Int = .{
.bits = @bitSizeOf(@TypeOf(string.*)) - 8, // (- 8) to exclude sentinel 0
.signedness = .unsigned,
}
}) {
const byteLength = @bitSizeOf(@TypeOf(string.*))/8 - 1;
const expectedType = *const [byteLength: 0]u8;
if (@TypeOf(string) != expectedType) {
@compileError("expected : "++@typeName(expectedType)++", got: "++@typeName(@TypeOf(string)));
}

return @bitCast(@as(*const [byteLength]u8, string).*);
}

const HEX_CHAR = blk: {
var all = std.mem.zeroes([255]bool);
for ('a'..('f' + 1)) |b| all[b] = true;
Expand Down Expand Up @@ -283,3 +277,20 @@ test "url: isValid" {
}
}
}

test "toUint" {
const ASCII_x = @as(u8, @bitCast([1]u8{ 'x' }));
const ASCII_ab = @as(u16, @bitCast([2]u8{ 'a', 'b' }));
const ASCII_xyz = @as(u24, @bitCast([3]u8{ 'x', 'y', 'z' }));
const ASCII_abcd = @as(u32, @bitCast([4]u8{ 'a', 'b', 'c', 'd' }));

try t.expectEqual(ASCII_x, asUint("x"));
try t.expectEqual(ASCII_ab, asUint("ab"));
try t.expectEqual(ASCII_xyz, asUint("xyz"));
try t.expectEqual(ASCII_abcd, asUint("abcd"));

try t.expectEqual(u8, @TypeOf(asUint("x")));
try t.expectEqual(u16, @TypeOf(asUint("ab")));
try t.expectEqual(u24, @TypeOf(asUint("xyz")));
try t.expectEqual(u32, @TypeOf(asUint("abcd")));
}

0 comments on commit 69665a5

Please sign in to comment.