hare

The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

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:
Mscripts/gen-stdlib | 13++++++++++---
Mstdlib.mk | 7++++---
Auuid/+test.ha | 20++++++++++++++++++++
Muuid/uuid.ha | 50+++++++++++++++++++++++++++++++++++++++++++++++++-
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(), + }; +};