summaryrefslogtreecommitdiff
path: root/src/libzisp/value/ptr.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/libzisp/value/ptr.zig')
-rw-r--r--src/libzisp/value/ptr.zig176
1 files changed, 176 insertions, 0 deletions
diff --git a/src/libzisp/value/ptr.zig b/src/libzisp/value/ptr.zig
new file mode 100644
index 0000000..4bf92b6
--- /dev/null
+++ b/src/libzisp/value/ptr.zig
@@ -0,0 +1,176 @@
+const std = @import("std");
+
+const Value = @import("../value.zig").Value;
+
+// Zig API
+
+pub fn check(v: Value) bool {
+ return v.isPacked() and v.ptr.is_ptr;
+}
+
+pub fn assert(v: Value) void {
+ if (!check(v)) {
+ v.dump();
+ @panic("not a pointer");
+ }
+}
+
+// Foreign Pointers
+
+pub fn checkForeign(v: Value) bool {
+ return check(v) and v.ptr.foreign;
+}
+
+pub fn assertForeign(v: Value) void {
+ if (!checkForeign(v)) {
+ v.dump();
+ @panic("not foreign pointer");
+ }
+}
+
+pub fn packForeign(int: u50) Value {
+ return .{ .fptr = .{int} };
+}
+
+pub fn unpackForeign(v: Value) u64 {
+ assertForeign(v);
+ return v.ptr.value.foreign;
+}
+
+// Zisp Pointers
+
+pub fn checkZisp(v: Value) bool {
+ return check(v) and !v.ptr.foreign;
+}
+
+pub fn assertZisp(v: Value) void {
+ if (!checkZisp(v)) {
+ v.dump();
+ @panic("not zisp pointer");
+ }
+}
+
+pub fn checkWeak(v: Value) bool {
+ return checkZisp(v) and v.ptr.weak;
+}
+
+pub fn assertWeak(v: Value) void {
+ if (!checkWeak(v)) {
+ v.dump();
+ @panic("not weak zisp pointer");
+ }
+}
+
+pub fn checkNormal(v: Value) bool {
+ return checkZisp(v) and !v.ptr.weak;
+}
+
+pub fn assertNormal(v: Value) void {
+ if (!checkNormal(v)) {
+ v.dump();
+ @panic("not normal zisp pointer");
+ }
+}
+
+pub fn packZisp(ptr: *anyopaque, tag: Tag, weak: bool) Value {
+ return .{ .ptr = .{
+ .value = tagPtr(ptr, tag),
+ .weak = weak,
+ } };
+}
+
+pub fn pack(ptr: *anyopaque, tag: Tag) Value {
+ return packZisp(ptr, tag, false);
+}
+
+pub fn packWeak(ptr: *anyopaque, tag: Tag) Value {
+ return packZisp(ptr, tag, true);
+}
+
+// Unpacks weak as well; no need for a separate fn.
+pub fn unpack(v: Value) struct { ptr: *anyopaque, tag: Tag } {
+ assertZisp(v);
+ return untagPtr(v.ptr.value.tagged);
+}
+
+// Weak pointers may be null.
+pub fn isNull(v: Value) bool {
+ assertWeak(v);
+ const ptr, _ = untagPtr(v.ptr.value.tagged);
+ return @intFromPtr(ptr) == 0;
+}
+
+pub fn tagPtr(ptr: *anyopaque, tag: Tag) u49 {
+ const int: u64 = @intFromPtr(ptr);
+ const untagged: u49 = @truncate(int);
+ return untagged << 1 | @intFromEnum(tag);
+}
+
+pub fn untagPtr(tagged: 49) struct { ptr: *anyopaque, tag: Tag } {
+ const untagged: u49 = tagged >> 1 & 0xfffffffffff0;
+ const ptr: *anyopaque = @ptrFromInt(untagged);
+ const int: u4 = @truncate(tagged);
+ const tag: Tag = @enumFromInt(int);
+ return .{ .ptr = ptr, .tag = tag };
+}
+
+pub const Tag = enum(u4) {
+ /// 1. Strings / Symbols
+ string,
+ /// 2. Bignums / Ratnums
+ number,
+ /// 3. Pairs ([2]Value)
+ pair,
+ /// 4. Vector, bytevector, etc.
+ array,
+ /// 5. Ordered hash table
+ table,
+ /// 6. String buffer
+ text,
+ /// 7. Class, interface, etc.
+ role,
+ /// 8. Instance, basically
+ actor,
+ /// 9. I/O Port
+ port,
+ /// 10. Procedure
+ proc,
+ /// 11. Continuation
+ cont,
+ /// Other
+ other = 15,
+};
+
+// Zisp API
+
+pub fn predForeign(v: Value) Value {
+ return Value.boole.pack(checkForeign(v));
+}
+
+pub fn makeWeak(v: Value) Value {
+ assertNormal(v);
+ var copy = v;
+ copy.ptr.weak = true;
+ return copy;
+}
+
+pub fn predWeak(v: Value) Value {
+ const isWeak = checkWeak(v);
+ return Value.boole.pack(isWeak);
+}
+
+pub fn predWeakNull(v: Value) Value {
+ assertWeak(v);
+ return Value.boole.pack(v.ptr.weak);
+}
+
+pub fn getWeak(v: Value) Value {
+ assertWeak(v);
+ if (isNull(v)) {
+ return Value.boole.pack(false);
+ } else {
+ var copy = v;
+ copy.ptr.weak = false;
+ return copy;
+ }
+}