commit 79768eb8a3fbd5a7d3001bc6a60247d0c4c41fca
parent e9c32daa3d03dbca69a4beefcfca438f617a91f6
Author: Drew DeVault <sir@cmpwn.com>
Date: Thu, 6 May 2021 10:05:20 -0400
uuid: implement decode, decodestr
Signed-off-by: Drew DeVault <sir@cmpwn.com>
Diffstat:
4 files changed, 83 insertions(+), 7 deletions(-)
diff --git a/scripts/gen-stdlib b/scripts/gen-stdlib
@@ -724,9 +724,16 @@ unix_tty() {
}
uuid() {
- gen_srcs uuid \
- uuid.ha
- gen_ssa uuid crypto::random strio fmt endian io bytes
+ if [ $testing -eq 0 ]
+ then
+ gen_srcs uuid \
+ uuid.ha
+ else
+ gen_srcs uuid \
+ uuid.ha \
+ +test.ha
+ fi
+ gen_ssa uuid crypto::random strio fmt endian io bytes bufio strings strconv
}
printf '# This file is generated by the gen-stdlib script, do not edit it by hand\n\n'
diff --git a/stdlib.mk b/stdlib.mk
@@ -948,7 +948,7 @@ $(HARECACHE)/unix/tty/unix_tty.ssa: $(stdlib_unix_tty_srcs) $(stdlib_rt) $(stdli
stdlib_uuid_srcs= \
$(STDLIB)/uuid/uuid.ha
-$(HARECACHE)/uuid/uuid.ssa: $(stdlib_uuid_srcs) $(stdlib_rt) $(stdlib_crypto_random) $(stdlib_strio) $(stdlib_fmt) $(stdlib_endian) $(stdlib_io) $(stdlib_bytes)
+$(HARECACHE)/uuid/uuid.ssa: $(stdlib_uuid_srcs) $(stdlib_rt) $(stdlib_crypto_random) $(stdlib_strio) $(stdlib_fmt) $(stdlib_endian) $(stdlib_io) $(stdlib_bytes) $(stdlib_bufio) $(stdlib_strings) $(stdlib_strconv)
@printf 'HAREC \t$@\n'
@mkdir -p $(HARECACHE)/uuid
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nuuid \
@@ -1926,9 +1926,10 @@ $(TESTCACHE)/unix/tty/unix_tty.ssa: $(testlib_unix_tty_srcs) $(testlib_rt) $(tes
# uuid
testlib_uuid_srcs= \
- $(STDLIB)/uuid/uuid.ha
+ $(STDLIB)/uuid/uuid.ha \
+ $(STDLIB)/uuid/+test.ha
-$(TESTCACHE)/uuid/uuid.ssa: $(testlib_uuid_srcs) $(testlib_rt) $(testlib_crypto_random) $(testlib_strio) $(testlib_fmt) $(testlib_endian) $(testlib_io) $(testlib_bytes)
+$(TESTCACHE)/uuid/uuid.ssa: $(testlib_uuid_srcs) $(testlib_rt) $(testlib_crypto_random) $(testlib_strio) $(testlib_fmt) $(testlib_endian) $(testlib_io) $(testlib_bytes) $(testlib_bufio) $(testlib_strings) $(testlib_strconv)
@printf 'HAREC \t$@\n'
@mkdir -p $(TESTCACHE)/uuid
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nuuid \
diff --git a/uuid/+test.ha b/uuid/+test.ha
@@ -0,0 +1,20 @@
+@test fn decode() void = {
+ let in = "3ded910c-8080-4bc8-af39-b6cccee36741";
+ let id = match (decodestr(in)) {
+ invalid => abort(),
+ u: uuid => u,
+ };
+ assert(compare(id, [
+ 0x3d, 0xed, 0x91, 0x0c, 0x80, 0x80, 0x4b, 0xc8,
+ 0xaf, 0x39, 0xb6, 0xcc, 0xce, 0xe3, 0x67, 0x41,
+ ]));
+ assert(decodestr("hello world") is invalid);
+};
+
+@test fn encode() void = {
+ let in: uuid = [
+ 0x3d, 0xed, 0x91, 0x0c, 0x80, 0x80, 0x4b, 0xc8,
+ 0xaf, 0x39, 0xb6, 0xcc, 0xce, 0xe3, 0x67, 0x41,
+ ];
+ assert(encodestr(in) == "3ded910c-8080-4bc8-af39-b6cccee36741");
+};
diff --git a/uuid/uuid.ha b/uuid/uuid.ha
@@ -1,10 +1,12 @@
+use bufio;
use bytes;
use crypto::random;
use endian;
use fmt;
use io;
+use strconv;
+use strings;
use strio;
-// TODO: decode, decodestr
// A UUID.
export type uuid = [16]u8;
@@ -16,6 +18,9 @@ export def UUID_URILEN: size = 45;
// The "nil" UUID, with all bits set to zero.
export const nil: uuid = [0...];
+// Returned from [[decode]] if an invalid UUID is observed.
+export type invalid = !void;
+
// Octet offsets of various fields as defined by the RFC.
def TIME_LOW: size = 0;
def TIME_MID: size = 4;
@@ -86,3 +91,46 @@ export fn encodeuri(in: uuid) str = {
uri(sink, in) as size;
return strio::string(sink);
};
+
+// Decodes a UUID as a string from an [[io::stream]].
+export fn decode(in: *io::stream) (uuid | invalid | io::error) = {
+ let u: uuid = [0...];
+ for (let i = 0z; i < len(u); i += 1) {
+ let buf: [2]u8 = [0...];
+ match (io::read(in, buf)?) {
+ io::EOF => return invalid,
+ z: size => assert(z == len(buf)),
+ };
+ u[i] = match (strconv::stou8b(
+ strings::fromutf8_unsafe(buf),
+ strconv::base::HEX)) {
+ strconv::overflow => abort(),
+ strconv::invalid => return invalid,
+ u: u8 => u,
+ };
+ if (i + 1 == TIME_MID
+ || i + 1 == TIME_HI_AND_VERSION
+ || i + 1 == CLOCK_SEQ_HI_AND_RESERVED
+ || i + 1 == NODE) {
+ match (io::read(in, buf[..1])?) {
+ io::EOF => return invalid,
+ z: size => assert(z == 1),
+ };
+ if (buf[0] != '-': u32: u8) {
+ return invalid;
+ };
+ };
+ };
+ return u;
+};
+
+// Decodes a UUID from a string.
+export fn decodestr(in: str) (uuid | invalid) = {
+ let buf = bufio::fixed(strings::toutf8(in), io::mode::READ);
+ defer io::close(buf);
+ return match (decode(buf)) {
+ u: uuid => u,
+ invalid => invalid,
+ err: io::error => abort(),
+ };
+};