aboutsummaryrefslogtreecommitdiff
path: root/stdlib
diff options
context:
space:
mode:
authorBruce Hill <bruce@bruce-hill.com>2025-03-18 17:00:30 -0400
committerBruce Hill <bruce@bruce-hill.com>2025-03-18 17:00:30 -0400
commit6086b2dbda874d5538e878101c7ee98a10fdeddb (patch)
tree9e96e8e279a433cc5484358f10b15f87634463f9 /stdlib
parentbc054ab6c6b6974c315cce21abb3405e443acd3e (diff)
Expose PathType as a proper enum
Diffstat (limited to 'stdlib')
-rw-r--r--stdlib/datatypes.h7
-rw-r--r--stdlib/paths.c86
-rw-r--r--stdlib/paths.h1
3 files changed, 58 insertions, 36 deletions
diff --git a/stdlib/datatypes.h b/stdlib/datatypes.h
index dc121c82..b81ff741 100644
--- a/stdlib/datatypes.h
+++ b/stdlib/datatypes.h
@@ -97,7 +97,12 @@ typedef struct Text_s {
#define OptionalPattern_t Text_t
typedef struct {
- enum { PATH_NONE, PATH_RELATIVE, PATH_ABSOLUTE, PATH_HOME } type;
+ enum { PATH_NONE, PATH_RELATIVE, PATH_ABSOLUTE, PATH_HOME } $tag;
+} PathType_t;
+#define OptionalPathType_t PathType_t
+
+typedef struct {
+ PathType_t type;
Array_t components;
} Path_t;
#define OptionalPath_t Path_t
diff --git a/stdlib/paths.c b/stdlib/paths.c
index bac37b27..ba98e9fb 100644
--- a/stdlib/paths.c
+++ b/stdlib/paths.c
@@ -17,11 +17,13 @@
#include <unistr.h>
#include "arrays.h"
+#include "enums.h"
#include "files.h"
#include "integers.h"
#include "optionals.h"
#include "paths.h"
#include "patterns.h"
+#include "structs.h"
#include "text.h"
#include "types.h"
#include "util.h"
@@ -30,7 +32,9 @@
#include "siphash.h"
#include "siphash-internals.h"
-static const Path_t HOME_PATH = {.type=PATH_HOME}, ROOT_PATH = {.type=PATH_ABSOLUTE}, CURDIR_PATH = {.type=PATH_RELATIVE};
+static const Path_t HOME_PATH = {.type.$tag=PATH_HOME},
+ ROOT_PATH = {.type.$tag=PATH_ABSOLUTE},
+ CURDIR_PATH = {.type.$tag=PATH_RELATIVE};
static void clean_components(Array_t *components)
{
@@ -60,16 +64,16 @@ public Path_t Path$from_str(const char *str)
Path_t result = {.components={}};
if (str[0] == '/') {
- result.type = PATH_ABSOLUTE;
+ result.type.$tag = PATH_ABSOLUTE;
str += 1;
} else if (str[0] == '~' && str[1] == '/') {
- result.type = PATH_HOME;
+ result.type.$tag = PATH_HOME;
str += 2;
} else if (str[0] == '.' && str[1] == '/') {
- result.type = PATH_RELATIVE;
+ result.type.$tag = PATH_RELATIVE;
str += 2;
} else {
- result.type = PATH_RELATIVE;
+ result.type.$tag = PATH_RELATIVE;
}
while (str && *str) {
@@ -100,12 +104,12 @@ public Path_t Path$from_text(Text_t text)
public Path_t Path$expand_home(Path_t path)
{
- if (path.type == PATH_HOME) {
+ if (path.type.$tag == PATH_HOME) {
Path_t pwd = Path$from_str(getenv("HOME"));
Array_t components = Array$concat(pwd.components, path.components, sizeof(Text_t));
assert(components.length == path.components.length + pwd.components.length);
clean_components(&components);
- path = (Path_t){.type=PATH_ABSOLUTE, .components=components};
+ path = (Path_t){.type.$tag=PATH_ABSOLUTE, .components=components};
}
return path;
}
@@ -116,7 +120,7 @@ public Path_t Path$_concat(int n, Path_t items[n])
Path_t result = items[0];
ARRAY_INCREF(result.components);
for (int i = 1; i < n; i++) {
- if (items[i].type != PATH_RELATIVE)
+ if (items[i].type.$tag != PATH_RELATIVE)
fail("Cannot concatenate an absolute or home-based path onto another path: (%s)\n",
Path$as_c_string(items[i]));
Array$insert_all(&result.components, items[i].components, I(0), sizeof(Text_t));
@@ -127,8 +131,8 @@ public Path_t Path$_concat(int n, Path_t items[n])
public Path_t Path$resolved(Path_t path, Path_t relative_to)
{
- if (path.type == PATH_RELATIVE && !(relative_to.type == PATH_RELATIVE && relative_to.components.length == 0)) {
- Path_t result = {.type=relative_to.type};
+ if (path.type.$tag == PATH_RELATIVE && !(relative_to.type.$tag == PATH_RELATIVE && relative_to.components.length == 0)) {
+ Path_t result = {.type.$tag=relative_to.type.$tag};
result.components = relative_to.components;
ARRAY_INCREF(result.components);
Array$insert_all(&result.components, path.components, I(0), sizeof(Text_t));
@@ -140,11 +144,11 @@ public Path_t Path$resolved(Path_t path, Path_t relative_to)
public Path_t Path$relative_to(Path_t path, Path_t relative_to)
{
- if (path.type != relative_to.type)
+ if (path.type.$tag != relative_to.type.$tag)
fail("Cannot create a path relative to a different path with a mismatching type: (%k) relative to (%k)",
(Text_t[1]){Path$as_text(&path, false, &Path$info)}, (Text_t[1]){Path$as_text(&relative_to, false, &Path$info)});
- Path_t result = {.type=PATH_RELATIVE};
+ Path_t result = {.type.$tag=PATH_RELATIVE};
int64_t shared = 0;
for (; shared < path.components.length && shared < relative_to.components.length; shared++) {
Text_t *p = (Text_t*)(path.components.data + shared*path.components.stride);
@@ -532,13 +536,13 @@ public Path_t Path$write_unique(Path_t path, Text_t text)
public Path_t Path$parent(Path_t path)
{
- if (path.type == PATH_ABSOLUTE && path.components.length == 0) {
+ if (path.type.$tag == PATH_ABSOLUTE && path.components.length == 0) {
return path;
} else if (path.components.length > 0 && !Text$equal_values(*(Text_t*)(path.components.data + path.components.stride*(path.components.length-1)),
Text(".."))) {
- return (Path_t){.type=path.type, .components=Array$slice(path.components, I(1), I(-2))};
+ return (Path_t){.type.$tag=path.type.$tag, .components=Array$slice(path.components, I(1), I(-2))};
} else {
- Path_t result = {.type=path.type, .components=path.components};
+ Path_t result = {.type.$tag=path.type.$tag, .components=path.components};
ARRAY_INCREF(result.components);
Array$insert_value(&result.components, Text(".."), I(0), sizeof(Text_t));
return result;
@@ -549,9 +553,9 @@ public PUREFUNC Text_t Path$base_name(Path_t path)
{
if (path.components.length >= 1)
return *(Text_t*)(path.components.data + path.components.stride*(path.components.length-1));
- else if (path.type == PATH_HOME)
+ else if (path.type.$tag == PATH_HOME)
return Text("~");
- else if (path.type == PATH_RELATIVE)
+ else if (path.type.$tag == PATH_RELATIVE)
return Text(".");
else
return EMPTY_TEXT;
@@ -573,7 +577,7 @@ public Text_t Path$extension(Path_t path, bool full)
public Path_t Path$with_component(Path_t path, Text_t component)
{
Path_t result = {
- .type=path.type,
+ .type.$tag=path.type.$tag,
.components=path.components,
};
ARRAY_INCREF(result.components);
@@ -588,7 +592,7 @@ public Path_t Path$with_extension(Path_t path, Text_t extension, bool replace)
fail("A path with no components can't have an extension!");
Path_t result = {
- .type=path.type,
+ .type.$tag=path.type.$tag,
.components=path.components,
};
ARRAY_INCREF(result.components);
@@ -675,7 +679,7 @@ public PUREFUNC uint64_t Path$hash(const void *obj, const TypeInfo_t *type)
(void)type;
Path_t *path = (Path_t*)obj;
siphash sh;
- siphashinit(&sh, (uint64_t)path->type);
+ siphashinit(&sh, (uint64_t)path->type.$tag);
for (int64_t i = 0; i < path->components.length; i++) {
uint64_t item_hash = Text$hash(path->components.data + i*path->components.stride, &Text$info);
siphashadd64bits(&sh, item_hash);
@@ -687,7 +691,7 @@ public PUREFUNC int32_t Path$compare(const void *va, const void *vb, const TypeI
{
(void)type;
Path_t *a = (Path_t*)va, *b = (Path_t*)vb;
- int diff = ((int)a->type - (int)b->type);
+ int diff = ((int)a->type.$tag - (int)b->type.$tag);
if (diff != 0) return diff;
return Array$compare(&a->components, &b->components, Array$info(&Text$info));
}
@@ -696,32 +700,32 @@ public PUREFUNC bool Path$equal(const void *va, const void *vb, const TypeInfo_t
{
(void)type;
Path_t *a = (Path_t*)va, *b = (Path_t*)vb;
- if (a->type != b->type) return false;
+ if (a->type.$tag != b->type.$tag) return false;
return Array$equal(&a->components, &b->components, Array$info(&Text$info));
}
public PUREFUNC bool Path$equal_values(Path_t a, Path_t b)
{
- if (a.type != b.type) return false;
+ if (a.type.$tag != b.type.$tag) return false;
return Array$equal(&a.components, &b.components, Array$info(&Text$info));
}
public const char *Path$as_c_string(Path_t path)
{
if (path.components.length == 0) {
- if (path.type == PATH_ABSOLUTE) return "/";
- else if (path.type == PATH_RELATIVE) return ".";
- else if (path.type == PATH_HOME) return "~";
+ if (path.type.$tag == PATH_ABSOLUTE) return "/";
+ else if (path.type.$tag == PATH_RELATIVE) return ".";
+ else if (path.type.$tag == PATH_HOME) return "~";
}
size_t len = 0, capacity = 16;
char *buf = GC_MALLOC_ATOMIC(capacity);
- if (path.type == PATH_ABSOLUTE) {
+ if (path.type.$tag == PATH_ABSOLUTE) {
buf[len++] = '/';
- } else if (path.type == PATH_HOME) {
+ } else if (path.type.$tag == PATH_HOME) {
buf[len++] = '~';
buf[len++] = '/';
- } else if (path.type == PATH_RELATIVE) {
+ } else if (path.type.$tag == PATH_RELATIVE) {
if (!Text$equal_values(*(Text_t*)path.components.data, Text(".."))) {
buf[len++] = '.';
buf[len++] = '/';
@@ -750,11 +754,11 @@ public Text_t Path$as_text(const void *obj, bool color, const TypeInfo_t *type)
if (!obj) return Text("Path");
Path_t *path = (Path_t*)obj;
Text_t text = Text$join(Text("/"), path->components);
- if (path->type == PATH_HOME)
+ if (path->type.$tag == PATH_HOME)
text = Text$concat(path->components.length > 0 ? Text("~/") : Text("~"), text);
- else if (path->type == PATH_ABSOLUTE)
+ else if (path->type.$tag == PATH_ABSOLUTE)
text = Text$concat(Text("/"), text);
- else if (path->type == PATH_RELATIVE && (path->components.length == 0 || !Text$equal_values(*(Text_t*)(path->components.data), Text(".."))))
+ else if (path->type.$tag == PATH_RELATIVE && (path->components.length == 0 || !Text$equal_values(*(Text_t*)(path->components.data), Text(".."))))
text = Text$concat(path->components.length > 0 ? Text("./") : Text("."), text);
if (color)
@@ -766,14 +770,14 @@ public Text_t Path$as_text(const void *obj, bool color, const TypeInfo_t *type)
public CONSTFUNC bool Path$is_none(const void *obj, const TypeInfo_t *type)
{
(void)type;
- return ((Path_t*)obj)->type == PATH_NONE;
+ return ((Path_t*)obj)->type.$tag == PATH_NONE;
}
public void Path$serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *type)
{
(void)type;
Path_t *path = (Path_t*)obj;
- fputc((int)path->type, out);
+ fputc((int)path->type.$tag, out);
Array$serialize(&path->components, out, pointers, Array$info(&Text$info));
}
@@ -781,7 +785,7 @@ public void Path$deserialize(FILE *in, void *obj, Array_t *pointers, const TypeI
{
(void)type;
Path_t path = {};
- path.type = fgetc(in);
+ path.type.$tag = fgetc(in);
Array$deserialize(in, &path.components, pointers, Array$info(&Text$info));
*(Path_t*)obj = path;
}
@@ -801,4 +805,16 @@ public const TypeInfo_t Path$info = {
}
};
+public const TypeInfo_t PathType$info = {
+ .size=sizeof(PathType_t),
+ .align=__alignof__(PathType_t),
+ .metamethods=PackedDataEnum$metamethods,
+ .tag=EnumInfo,
+ .EnumInfo={
+ .name="PathType",
+ .num_tags=3,
+ .tags=((NamedType_t[3]){{.name="Relative"}, {.name="Absolute"}, {.name="Home"}}),
+ },
+};
+
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/stdlib/paths.h b/stdlib/paths.h
index f65bd3ca..6c6cebd3 100644
--- a/stdlib/paths.h
+++ b/stdlib/paths.h
@@ -65,6 +65,7 @@ void Path$serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInf
void Path$deserialize(FILE *in, void *obj, Array_t *pointers, const TypeInfo_t *type);
extern const TypeInfo_t Path$info;
+extern const TypeInfo_t PathType$info;
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0