@shd101wyy/yo 0.1.26 → 0.1.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/skills/yo-async-effects/SKILL.md +4 -4
- package/.github/skills/yo-async-effects/async-effects-recipes.md +34 -34
- package/.github/skills/yo-core-patterns/SKILL.md +1 -1
- package/.github/skills/yo-core-patterns/core-patterns-cheatsheet.md +26 -26
- package/.github/skills/yo-project-workflow/SKILL.md +6 -3
- package/.github/skills/yo-project-workflow/workflow-cheatsheet.md +34 -11
- package/.github/skills/yo-syntax/SKILL.md +7 -6
- package/.github/skills/yo-syntax/syntax-cheatsheet.md +73 -60
- package/.github/skills/yo-wasm-integration/wasm-integration-cheatsheet.md +3 -3
- package/README.md +10 -8
- package/out/cjs/index.cjs +456 -438
- package/out/cjs/yo-cli.cjs +576 -543
- package/out/cjs/yo-lsp.cjs +559 -532
- package/out/esm/index.mjs +281 -263
- package/out/types/src/formatter.d.ts +11 -0
- package/out/types/src/lsp/formatting.d.ts +2 -0
- package/out/types/src/tests/formatter.test.d.ts +1 -0
- package/out/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/std/alg/hash.yo +13 -21
- package/std/allocator.yo +25 -40
- package/std/async.yo +3 -7
- package/std/build.yo +105 -151
- package/std/cli/arg_parser.yo +184 -169
- package/std/collections/array_list.yo +350 -314
- package/std/collections/btree_map.yo +142 -131
- package/std/collections/deque.yo +132 -128
- package/std/collections/hash_map.yo +542 -566
- package/std/collections/hash_set.yo +623 -687
- package/std/collections/linked_list.yo +275 -293
- package/std/collections/ordered_map.yo +113 -85
- package/std/collections/priority_queue.yo +73 -73
- package/std/crypto/md5.yo +191 -95
- package/std/crypto/random.yo +56 -64
- package/std/crypto/sha256.yo +151 -107
- package/std/encoding/base64.yo +87 -81
- package/std/encoding/hex.yo +43 -50
- package/std/encoding/html.yo +56 -81
- package/std/encoding/html_char_utils.yo +7 -13
- package/std/encoding/html_entities.yo +2248 -2253
- package/std/encoding/json.yo +316 -224
- package/std/encoding/punycode.yo +86 -116
- package/std/encoding/toml.yo +67 -66
- package/std/encoding/utf16.yo +37 -44
- package/std/env.yo +62 -91
- package/std/error.yo +7 -15
- package/std/fmt/display.yo +5 -9
- package/std/fmt/index.yo +8 -14
- package/std/fmt/to_string.yo +330 -315
- package/std/fmt/writer.yo +58 -87
- package/std/fs/dir.yo +83 -102
- package/std/fs/file.yo +147 -180
- package/std/fs/metadata.yo +45 -78
- package/std/fs/temp.yo +55 -65
- package/std/fs/types.yo +27 -40
- package/std/fs/walker.yo +53 -68
- package/std/gc.yo +5 -8
- package/std/glob.yo +30 -43
- package/std/http/client.yo +107 -120
- package/std/http/http.yo +106 -96
- package/std/http/index.yo +4 -6
- package/std/imm/list.yo +88 -93
- package/std/imm/map.yo +528 -464
- package/std/imm/set.yo +52 -57
- package/std/imm/sorted_map.yo +340 -286
- package/std/imm/sorted_set.yo +57 -63
- package/std/imm/string.yo +404 -345
- package/std/imm/vec.yo +173 -181
- package/std/io/reader.yo +3 -6
- package/std/io/writer.yo +4 -8
- package/std/libc/assert.yo +5 -9
- package/std/libc/ctype.yo +32 -22
- package/std/libc/dirent.yo +26 -25
- package/std/libc/errno.yo +164 -90
- package/std/libc/fcntl.yo +52 -45
- package/std/libc/float.yo +66 -44
- package/std/libc/limits.yo +42 -33
- package/std/libc/math.yo +53 -82
- package/std/libc/signal.yo +72 -47
- package/std/libc/stdatomic.yo +217 -188
- package/std/libc/stdint.yo +5 -29
- package/std/libc/stdio.yo +5 -29
- package/std/libc/stdlib.yo +32 -39
- package/std/libc/string.yo +5 -23
- package/std/libc/sys/stat.yo +58 -56
- package/std/libc/time.yo +5 -19
- package/std/libc/unistd.yo +5 -20
- package/std/libc/wctype.yo +6 -9
- package/std/libc/windows.yo +26 -30
- package/std/log.yo +41 -55
- package/std/net/addr.yo +102 -97
- package/std/net/dns.yo +27 -28
- package/std/net/errors.yo +50 -49
- package/std/net/tcp.yo +113 -124
- package/std/net/udp.yo +55 -66
- package/std/os/env.yo +35 -33
- package/std/os/signal.yo +15 -25
- package/std/path.yo +276 -311
- package/std/prelude.yo +6304 -4315
- package/std/process/command.yo +87 -103
- package/std/process/index.yo +12 -31
- package/std/regex/compiler.yo +196 -95
- package/std/regex/flags.yo +58 -39
- package/std/regex/index.yo +157 -173
- package/std/regex/match.yo +20 -31
- package/std/regex/node.yo +134 -152
- package/std/regex/parser.yo +283 -259
- package/std/regex/unicode.yo +172 -202
- package/std/regex/vm.yo +155 -171
- package/std/string/index.yo +5 -7
- package/std/string/rune.yo +45 -55
- package/std/string/string.yo +937 -964
- package/std/string/string_builder.yo +94 -104
- package/std/string/unicode.yo +46 -64
- package/std/sync/channel.yo +72 -73
- package/std/sync/cond.yo +31 -36
- package/std/sync/mutex.yo +30 -32
- package/std/sync/once.yo +13 -16
- package/std/sync/rwlock.yo +26 -31
- package/std/sync/waitgroup.yo +20 -25
- package/std/sys/advise.yo +16 -24
- package/std/sys/bufio/buf_reader.yo +77 -93
- package/std/sys/bufio/buf_writer.yo +52 -65
- package/std/sys/clock.yo +4 -9
- package/std/sys/constants.yo +77 -61
- package/std/sys/copy.yo +4 -10
- package/std/sys/dir.yo +26 -43
- package/std/sys/dns.yo +41 -61
- package/std/sys/errors.yo +95 -103
- package/std/sys/events.yo +45 -57
- package/std/sys/externs.yo +319 -267
- package/std/sys/fallocate.yo +7 -11
- package/std/sys/fcntl.yo +14 -22
- package/std/sys/file.yo +26 -40
- package/std/sys/future.yo +5 -8
- package/std/sys/iov.yo +12 -25
- package/std/sys/lock.yo +12 -13
- package/std/sys/mmap.yo +38 -43
- package/std/sys/path.yo +3 -8
- package/std/sys/perm.yo +7 -21
- package/std/sys/pipe.yo +5 -12
- package/std/sys/process.yo +23 -29
- package/std/sys/seek.yo +10 -12
- package/std/sys/signal.yo +7 -13
- package/std/sys/signals.yo +52 -35
- package/std/sys/socket.yo +63 -58
- package/std/sys/socketpair.yo +3 -6
- package/std/sys/sockinfo.yo +11 -20
- package/std/sys/statfs.yo +11 -34
- package/std/sys/statx.yo +25 -52
- package/std/sys/sysinfo.yo +15 -20
- package/std/sys/tcp.yo +62 -92
- package/std/sys/temp.yo +5 -9
- package/std/sys/time.yo +5 -15
- package/std/sys/timer.yo +6 -11
- package/std/sys/tty.yo +10 -18
- package/std/sys/udp.yo +22 -39
- package/std/sys/umask.yo +3 -6
- package/std/sys/unix.yo +33 -52
- package/std/testing/bench.yo +49 -52
- package/std/thread.yo +10 -15
- package/std/time/datetime.yo +105 -89
- package/std/time/duration.yo +43 -56
- package/std/time/instant.yo +13 -18
- package/std/time/sleep.yo +5 -9
- package/std/url/index.yo +184 -209
- package/std/worker.yo +6 -10
package/std/fmt/writer.yo
CHANGED
|
@@ -11,154 +11,132 @@
|
|
|
11
11
|
//! .write_byte(u8(33));
|
|
12
12
|
//! s := w.to_string(); // "hello world!"
|
|
13
13
|
//! ```
|
|
14
|
-
|
|
15
|
-
{
|
|
16
|
-
{
|
|
17
|
-
{
|
|
18
|
-
{ snprintf } :: import "../libc/stdio";
|
|
19
|
-
|
|
14
|
+
{ String } :: import("../string");
|
|
15
|
+
{ ArrayList } :: import("../collections/array_list");
|
|
16
|
+
{ rune } :: import("../string/rune");
|
|
17
|
+
{ snprintf } :: import("../libc/stdio");
|
|
20
18
|
/// Text alignment for padded output.
|
|
21
19
|
Alignment :: enum(Left, Right, Center);
|
|
22
|
-
export
|
|
23
|
-
|
|
20
|
+
export(Alignment);
|
|
24
21
|
/// Chainable string builder backed by `ArrayList(u8)`.
|
|
25
22
|
/// Useful for constructing formatted strings without intermediate allocations.
|
|
26
23
|
Writer :: object(
|
|
27
24
|
buf : ArrayList(u8)
|
|
28
25
|
);
|
|
29
|
-
|
|
30
|
-
|
|
26
|
+
impl(
|
|
27
|
+
Writer,
|
|
31
28
|
/// Create a new empty Writer.
|
|
32
29
|
new : (fn() -> Self)(
|
|
33
|
-
Self(buf: ArrayList(u8).new())
|
|
30
|
+
Self(buf : ArrayList(u8).new())
|
|
34
31
|
),
|
|
35
|
-
|
|
36
32
|
/// Create a Writer pre-allocated with the given byte capacity.
|
|
37
|
-
with_capacity : (fn(cap: usize) -> Self)(
|
|
38
|
-
Self(buf: ArrayList(u8).with_capacity(cap))
|
|
33
|
+
with_capacity : (fn(cap : usize) -> Self)(
|
|
34
|
+
Self(buf : ArrayList(u8).with_capacity(cap))
|
|
39
35
|
),
|
|
40
|
-
|
|
41
36
|
/// Append a `str` literal (byte slice) to the Writer.
|
|
42
|
-
write_str : (fn(self: Self, s: str) -> Self)({
|
|
37
|
+
write_str : (fn(self : Self, s : str) -> Self)({
|
|
43
38
|
i := usize(0);
|
|
44
|
-
while
|
|
45
|
-
(i = (i + usize(1))),
|
|
46
|
-
{
|
|
39
|
+
while(i < s.len(), i = (i + usize(1)), {
|
|
47
40
|
self.buf.push(s.bytes(i));
|
|
48
|
-
};
|
|
41
|
+
});
|
|
49
42
|
self
|
|
50
43
|
}),
|
|
51
|
-
|
|
52
44
|
/// Append a String (owned UTF-8) to the Writer.
|
|
53
|
-
write_string : (fn(self: Self, s: String) -> Self)({
|
|
45
|
+
write_string : (fn(self : Self, s : String) -> Self)({
|
|
54
46
|
bytes := s.as_bytes();
|
|
55
47
|
i := usize(0);
|
|
56
|
-
while
|
|
57
|
-
(i = (i + usize(1))),
|
|
58
|
-
{
|
|
48
|
+
while(i < bytes.len(), i = (i + usize(1)), {
|
|
59
49
|
self.buf.push(bytes.get(i).unwrap());
|
|
60
|
-
};
|
|
50
|
+
});
|
|
61
51
|
self
|
|
62
52
|
}),
|
|
63
|
-
|
|
64
53
|
/// Append a single byte to the Writer.
|
|
65
|
-
write_byte : (fn(self: Self, b: u8) -> Self)({
|
|
54
|
+
write_byte : (fn(self : Self, b : u8) -> Self)({
|
|
66
55
|
self.buf.push(b);
|
|
67
56
|
self
|
|
68
57
|
}),
|
|
69
|
-
|
|
70
58
|
/// Append an ArrayList(u8) of bytes to the Writer.
|
|
71
|
-
write_bytes : (fn(self: Self, data: ArrayList(u8)) -> Self)({
|
|
59
|
+
write_bytes : (fn(self : Self, data : ArrayList(u8)) -> Self)({
|
|
72
60
|
i := usize(0);
|
|
73
|
-
while
|
|
74
|
-
(i = (i + usize(1))),
|
|
75
|
-
{
|
|
61
|
+
while(i < data.len(), i = (i + usize(1)), {
|
|
76
62
|
self.buf.push(data.get(i).unwrap());
|
|
77
|
-
};
|
|
63
|
+
});
|
|
78
64
|
self
|
|
79
65
|
}),
|
|
80
|
-
|
|
81
66
|
/// Append a Unicode code point encoded as UTF-8.
|
|
82
|
-
write_rune : (fn(self: Self, r: rune) -> Self)({
|
|
67
|
+
write_rune : (fn(self : Self, r : rune) -> Self)({
|
|
83
68
|
v := u32(r.char);
|
|
84
69
|
cond(
|
|
85
70
|
(v < u32(0x80)) => {
|
|
86
71
|
self.buf.push(u8(v));
|
|
87
72
|
},
|
|
88
73
|
(v < u32(0x800)) => {
|
|
89
|
-
self.buf.push(u8(
|
|
90
|
-
self.buf.push(u8(
|
|
74
|
+
self.buf.push(u8(u32(0xC0) | (v >> u32(6))));
|
|
75
|
+
self.buf.push(u8(u32(0x80) | (v & u32(0x3F))));
|
|
91
76
|
},
|
|
92
77
|
(v < u32(0x10000)) => {
|
|
93
|
-
self.buf.push(u8(
|
|
94
|
-
self.buf.push(u8(
|
|
95
|
-
self.buf.push(u8(
|
|
78
|
+
self.buf.push(u8(u32(0xE0) | (v >> u32(12))));
|
|
79
|
+
self.buf.push(u8(u32(0x80) | ((v >> u32(6)) & u32(0x3F))));
|
|
80
|
+
self.buf.push(u8(u32(0x80) | (v & u32(0x3F))));
|
|
96
81
|
},
|
|
97
82
|
true => {
|
|
98
|
-
self.buf.push(u8(
|
|
99
|
-
self.buf.push(u8(
|
|
100
|
-
self.buf.push(u8(
|
|
101
|
-
self.buf.push(u8(
|
|
83
|
+
self.buf.push(u8(u32(0xF0) | (v >> u32(18))));
|
|
84
|
+
self.buf.push(u8(u32(0x80) | ((v >> u32(12)) & u32(0x3F))));
|
|
85
|
+
self.buf.push(u8(u32(0x80) | ((v >> u32(6)) & u32(0x3F))));
|
|
86
|
+
self.buf.push(u8(u32(0x80) | (v & u32(0x3F))));
|
|
102
87
|
}
|
|
103
88
|
);
|
|
104
89
|
self
|
|
105
90
|
}),
|
|
106
|
-
|
|
107
91
|
/// Append a signed 64-bit integer in decimal.
|
|
108
|
-
write_i64 : (fn(self: Self, n: i64) -> Self)({
|
|
92
|
+
write_i64 : (fn(self : Self, n : i64) -> Self)({
|
|
109
93
|
buf := Array(u8, usize(24)).fill(u8(0));
|
|
110
94
|
buf_ptr := &(buf(usize(0)));
|
|
111
95
|
snprintf(*(char)(buf_ptr), usize(24), "%lld", n);
|
|
112
96
|
s := String.from_cstr(buf_ptr).unwrap();
|
|
113
97
|
self.write_string(s)
|
|
114
98
|
}),
|
|
115
|
-
|
|
116
99
|
/// Append an unsigned 64-bit integer in decimal.
|
|
117
|
-
write_u64 : (fn(self: Self, n: u64) -> Self)({
|
|
100
|
+
write_u64 : (fn(self : Self, n : u64) -> Self)({
|
|
118
101
|
buf := Array(u8, usize(24)).fill(u8(0));
|
|
119
102
|
buf_ptr := &(buf(usize(0)));
|
|
120
103
|
snprintf(*(char)(buf_ptr), usize(24), "%llu", n);
|
|
121
104
|
s := String.from_cstr(buf_ptr).unwrap();
|
|
122
105
|
self.write_string(s)
|
|
123
106
|
}),
|
|
124
|
-
|
|
125
107
|
/// Append a 64-bit float with the given number of decimal places.
|
|
126
|
-
write_f64 : (fn(self: Self, n: f64, precision: i32) -> Self)({
|
|
108
|
+
write_f64 : (fn(self : Self, n : f64, precision : i32) -> Self)({
|
|
127
109
|
buf := Array(u8, usize(64)).fill(u8(0));
|
|
128
110
|
buf_ptr := &(buf(usize(0)));
|
|
129
111
|
snprintf(*(char)(buf_ptr), usize(64), "%.*f", precision, n);
|
|
130
112
|
s := String.from_cstr(buf_ptr).unwrap();
|
|
131
113
|
self.write_string(s)
|
|
132
114
|
}),
|
|
133
|
-
|
|
134
115
|
/// Append a bool as "true" or "false".
|
|
135
|
-
write_bool : (fn(self: Self, b: bool) -> Self)(
|
|
116
|
+
write_bool : (fn(self : Self, b : bool) -> Self)(
|
|
136
117
|
cond(
|
|
137
118
|
b => self.write_str("true"),
|
|
138
119
|
true => self.write_str("false")
|
|
139
120
|
)
|
|
140
121
|
),
|
|
141
|
-
|
|
142
122
|
/// Append an unsigned 64-bit integer in lowercase hexadecimal.
|
|
143
|
-
write_hex : (fn(self: Self, n: u64) -> Self)({
|
|
123
|
+
write_hex : (fn(self : Self, n : u64) -> Self)({
|
|
144
124
|
buf := Array(u8, usize(20)).fill(u8(0));
|
|
145
125
|
buf_ptr := &(buf(usize(0)));
|
|
146
126
|
snprintf(*(char)(buf_ptr), usize(20), "%llx", n);
|
|
147
127
|
s := String.from_cstr(buf_ptr).unwrap();
|
|
148
128
|
self.write_string(s)
|
|
149
129
|
}),
|
|
150
|
-
|
|
151
130
|
/// Append an unsigned 64-bit integer in octal.
|
|
152
|
-
write_octal : (fn(self: Self, n: u64) -> Self)({
|
|
131
|
+
write_octal : (fn(self : Self, n : u64) -> Self)({
|
|
153
132
|
buf := Array(u8, usize(24)).fill(u8(0));
|
|
154
133
|
buf_ptr := &(buf(usize(0)));
|
|
155
134
|
snprintf(*(char)(buf_ptr), usize(24), "%llo", n);
|
|
156
135
|
s := String.from_cstr(buf_ptr).unwrap();
|
|
157
136
|
self.write_string(s)
|
|
158
137
|
}),
|
|
159
|
-
|
|
160
138
|
/// Append an unsigned 64-bit integer in binary (no stdlib support — manual).
|
|
161
|
-
write_binary : (fn(self: Self, n: u64) -> Self)({
|
|
139
|
+
write_binary : (fn(self : Self, n : u64) -> Self)({
|
|
162
140
|
cond(
|
|
163
141
|
(n == u64(0)) => {
|
|
164
142
|
self.buf.push(u8(48)); // '0'
|
|
@@ -167,74 +145,67 @@ impl(Writer,
|
|
|
167
145
|
// Collect bits into a temporary ArrayList in reverse order
|
|
168
146
|
bits := ArrayList(u8).new();
|
|
169
147
|
v := n;
|
|
170
|
-
while
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
bits.push((bit + u8(48))); // '0' or '1'
|
|
175
|
-
};
|
|
148
|
+
while(v > u64(0), v = (v >> u64(1)), {
|
|
149
|
+
bit := u8((v & u64(1)) + u64(0));
|
|
150
|
+
bits.push(bit + u8(48)); // '0' or '1'
|
|
151
|
+
});
|
|
176
152
|
// Push in reverse order (most significant first)
|
|
177
153
|
i := bits.len();
|
|
178
|
-
while
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
self.buf.push(bits.get((i - usize(1))).unwrap());
|
|
182
|
-
};
|
|
154
|
+
while(i > usize(0), i = (i - usize(1)), {
|
|
155
|
+
self.buf.push(bits.get(i - usize(1)).unwrap());
|
|
156
|
+
});
|
|
183
157
|
}
|
|
184
158
|
);
|
|
185
159
|
self
|
|
186
160
|
}),
|
|
187
|
-
|
|
188
161
|
/// Append a str padded to width using the given pad rune and alignment.
|
|
189
|
-
write_padded : (fn(self: Self, s: str, width: usize, pad: rune, align: Alignment) -> Self)({
|
|
162
|
+
write_padded : (fn(self : Self, s : str, width : usize, pad : rune, align : Alignment) -> Self)({
|
|
190
163
|
len := s.len();
|
|
191
164
|
cond(
|
|
192
165
|
(len >= width) => self.write_str(s),
|
|
193
166
|
true => {
|
|
194
167
|
padding := (width - len);
|
|
195
|
-
match(
|
|
168
|
+
match(
|
|
169
|
+
align,
|
|
196
170
|
.Left => {
|
|
197
171
|
self.write_str(s);
|
|
198
172
|
i := usize(0);
|
|
199
|
-
while
|
|
173
|
+
while(i < padding, i = (i + usize(1)), {
|
|
200
174
|
self.write_rune(pad);
|
|
201
|
-
};
|
|
175
|
+
});
|
|
202
176
|
},
|
|
203
177
|
.Right => {
|
|
204
178
|
i := usize(0);
|
|
205
|
-
while
|
|
179
|
+
while(i < padding, i = (i + usize(1)), {
|
|
206
180
|
self.write_rune(pad);
|
|
207
|
-
};
|
|
181
|
+
});
|
|
208
182
|
self.write_str(s);
|
|
209
183
|
},
|
|
210
184
|
.Center => {
|
|
211
185
|
left_pad := (padding / usize(2));
|
|
212
186
|
right_pad := (padding - left_pad);
|
|
213
187
|
i := usize(0);
|
|
214
|
-
while
|
|
188
|
+
while(i < left_pad, i = (i + usize(1)), {
|
|
215
189
|
self.write_rune(pad);
|
|
216
|
-
};
|
|
190
|
+
});
|
|
217
191
|
self.write_str(s);
|
|
218
192
|
j := usize(0);
|
|
219
|
-
while
|
|
193
|
+
while(j < right_pad, j = (j + usize(1)), {
|
|
220
194
|
self.write_rune(pad);
|
|
221
|
-
};
|
|
195
|
+
});
|
|
222
196
|
}
|
|
223
197
|
);
|
|
224
198
|
self
|
|
225
199
|
}
|
|
226
200
|
)
|
|
227
201
|
}),
|
|
228
|
-
|
|
229
202
|
/// Consume the Writer and return an owned String.
|
|
230
|
-
to_string : (fn(self: Self) -> String)(
|
|
203
|
+
to_string : (fn(self : Self) -> String)(
|
|
231
204
|
String.from_bytes(self.buf)
|
|
232
205
|
),
|
|
233
|
-
|
|
234
206
|
/// Return the current byte length of the buffer.
|
|
235
|
-
len : (fn(self: Self) -> usize)(
|
|
207
|
+
len : (fn(self : Self) -> usize)(
|
|
236
208
|
self.buf.len()
|
|
237
209
|
)
|
|
238
210
|
);
|
|
239
|
-
|
|
240
|
-
export Writer;
|
|
211
|
+
export(Writer);
|
package/std/fs/dir.yo
CHANGED
|
@@ -20,28 +20,21 @@
|
|
|
20
20
|
//! io.await(remove_dir(Path.new(`/tmp/yo_test`)));
|
|
21
21
|
//! });
|
|
22
22
|
//! ```
|
|
23
|
-
|
|
24
|
-
{ GlobalAllocator } :: import "../allocator";
|
|
23
|
+
{ GlobalAllocator } :: import("../allocator");
|
|
25
24
|
{ malloc, free } :: GlobalAllocator;
|
|
26
|
-
{ ArrayList } :: import
|
|
27
|
-
open
|
|
28
|
-
{ Path } :: import
|
|
29
|
-
{ IOError } :: import
|
|
30
|
-
{ Error, AnyError, Exception } :: import
|
|
31
|
-
{ EEXIST, ENOENT } :: import
|
|
32
|
-
IO_dir :: import
|
|
33
|
-
IO_file :: import
|
|
34
|
-
{ platform, Platform } :: import
|
|
35
|
-
{
|
|
36
|
-
AT_FDCWD, AT_REMOVEDIR, O_RDONLY, O_DIRECTORY,
|
|
37
|
-
DEFAULT_DIR_MODE,
|
|
38
|
-
DT_REG, DT_DIR, DT_LNK
|
|
39
|
-
} :: import "../sys/constants";
|
|
40
|
-
|
|
25
|
+
{ ArrayList } :: import("../collections/array_list");
|
|
26
|
+
open(import("../string"));
|
|
27
|
+
{ Path } :: import("../path");
|
|
28
|
+
{ IOError } :: import("../sys/errors");
|
|
29
|
+
{ Error, AnyError, Exception } :: import("../error");
|
|
30
|
+
{ EEXIST, ENOENT } :: import("../libc/errno");
|
|
31
|
+
IO_dir :: import("../sys/dir");
|
|
32
|
+
IO_file :: import("../sys/file");
|
|
33
|
+
{ platform, Platform } :: import("../process");
|
|
34
|
+
{ AT_FDCWD, AT_REMOVEDIR, O_RDONLY, O_DIRECTORY, DEFAULT_DIR_MODE, DT_REG, DT_DIR, DT_LNK } :: import("../sys/constants");
|
|
41
35
|
// ============================================================================
|
|
42
36
|
// FileType enum
|
|
43
37
|
// ============================================================================
|
|
44
|
-
|
|
45
38
|
/// The type of a file system entry.
|
|
46
39
|
FileType :: enum(
|
|
47
40
|
/// A regular file.
|
|
@@ -53,47 +46,39 @@ FileType :: enum(
|
|
|
53
46
|
/// An unknown or unsupported file type.
|
|
54
47
|
Other
|
|
55
48
|
);
|
|
56
|
-
|
|
57
|
-
export FileType;
|
|
58
|
-
|
|
49
|
+
export(FileType);
|
|
59
50
|
// ============================================================================
|
|
60
51
|
// DirEntry
|
|
61
52
|
// ============================================================================
|
|
62
|
-
|
|
63
53
|
/// A directory entry containing the entry name, file type, and inode number.
|
|
64
54
|
DirEntry :: struct(
|
|
65
|
-
name
|
|
55
|
+
name : String,
|
|
66
56
|
file_type : FileType,
|
|
67
|
-
ino
|
|
57
|
+
ino : u64
|
|
68
58
|
);
|
|
69
|
-
|
|
70
|
-
export DirEntry;
|
|
71
|
-
|
|
59
|
+
export(DirEntry);
|
|
72
60
|
// ============================================================================
|
|
73
61
|
// Directory operations
|
|
74
62
|
// ============================================================================
|
|
75
|
-
|
|
76
63
|
/// Create a directory at the given path.
|
|
77
|
-
create_dir :: (fn(path: Path, using(io : IO)) -> Impl(Future(unit, IO, Exception)))(
|
|
64
|
+
create_dir :: (fn(path : Path, using(io : IO)) -> Impl(Future(unit, IO, Exception)))(
|
|
78
65
|
io.async((using(io, exn)) => {
|
|
79
66
|
cstr_bytes := path.to_string().to_cstr();
|
|
80
67
|
cstr := cstr_bytes.ptr().unwrap();
|
|
81
68
|
result := io.await(IO_dir.mkdir(AT_FDCWD, cstr, i32(DEFAULT_DIR_MODE)));
|
|
82
69
|
cond(
|
|
83
|
-
(result < i32(0)) => exn.throw(dyn
|
|
70
|
+
(result < i32(0)) => exn.throw(dyn(IOError.from_errno(i32(0) - result))),
|
|
84
71
|
true => ()
|
|
85
72
|
)
|
|
86
73
|
})
|
|
87
74
|
);
|
|
88
|
-
|
|
89
75
|
/// Create a directory (`str` path variant).
|
|
90
|
-
create_dir_str :: (fn(path: str, using(io : IO)) -> Impl(Future(unit, IO, Exception)))(
|
|
76
|
+
create_dir_str :: (fn(path : str, using(io : IO)) -> Impl(Future(unit, IO, Exception)))(
|
|
91
77
|
create_dir(Path.new(String.from(path)))
|
|
92
78
|
);
|
|
93
|
-
|
|
94
79
|
/// Create a directory and all missing parent directories.
|
|
95
80
|
/// Does not error if the directory already exists.
|
|
96
|
-
create_dir_all :: (fn(path: Path, using(io : IO)) -> Impl(Future(unit, IO, Exception)))(
|
|
81
|
+
create_dir_all :: (fn(path : Path, using(io : IO)) -> Impl(Future(unit, IO, Exception)))(
|
|
97
82
|
io.async((using(io, exn)) => {
|
|
98
83
|
path_s := path.to_string();
|
|
99
84
|
cstr_bytes := path_s.to_cstr();
|
|
@@ -121,14 +106,19 @@ create_dir_all :: (fn(path: Path, using(io : IO)) -> Impl(Future(unit, IO, Excep
|
|
|
121
106
|
first := bytes.get(usize(0)).unwrap();
|
|
122
107
|
second := bytes.get(usize(1)).unwrap();
|
|
123
108
|
is_drive_root := ((((first >= u8(65)) && (first <= u8(90))) || ((first >= u8(97)) && (first <= u8(122)))) && (second == u8(58)));
|
|
124
|
-
cond(
|
|
109
|
+
cond(
|
|
110
|
+
is_drive_root => {
|
|
111
|
+
i = usize(3);
|
|
112
|
+
},
|
|
113
|
+
true => ()
|
|
114
|
+
);
|
|
125
115
|
},
|
|
126
116
|
true => ()
|
|
127
117
|
);
|
|
128
118
|
},
|
|
129
119
|
true => ()
|
|
130
120
|
);
|
|
131
|
-
while
|
|
121
|
+
while(runtime(i < bytes.len()), {
|
|
132
122
|
b := bytes.get(i).unwrap();
|
|
133
123
|
cond(
|
|
134
124
|
((b == u8(47)) || (b == u8(92))) => {
|
|
@@ -140,7 +130,7 @@ create_dir_all :: (fn(path: Path, using(io : IO)) -> Impl(Future(unit, IO, Excep
|
|
|
140
130
|
// Ignore EEXIST errors
|
|
141
131
|
cond(
|
|
142
132
|
((r < i32(0)) && ((i32(0) - r) != i32(EEXIST))) => {
|
|
143
|
-
exn.throw(dyn
|
|
133
|
+
exn.throw(dyn(IOError.from_errno(i32(0) - r)));
|
|
144
134
|
},
|
|
145
135
|
true => ()
|
|
146
136
|
);
|
|
@@ -148,7 +138,7 @@ create_dir_all :: (fn(path: Path, using(io : IO)) -> Impl(Future(unit, IO, Excep
|
|
|
148
138
|
true => ()
|
|
149
139
|
);
|
|
150
140
|
i = (i + usize(1));
|
|
151
|
-
};
|
|
141
|
+
});
|
|
152
142
|
// Create the final directory
|
|
153
143
|
final_result := io.await(IO_dir.mkdir(AT_FDCWD, cstr, i32(DEFAULT_DIR_MODE)));
|
|
154
144
|
cond(
|
|
@@ -157,59 +147,51 @@ create_dir_all :: (fn(path: Path, using(io : IO)) -> Impl(Future(unit, IO, Excep
|
|
|
157
147
|
final_errno := (i32(0) - final_result);
|
|
158
148
|
cond(
|
|
159
149
|
(final_errno == i32(EEXIST)) => (),
|
|
160
|
-
true => exn.throw(dyn
|
|
150
|
+
true => exn.throw(dyn(IOError.from_errno(final_errno)))
|
|
161
151
|
)
|
|
162
152
|
}
|
|
163
153
|
)
|
|
164
154
|
},
|
|
165
|
-
true => exn.throw(dyn
|
|
155
|
+
true => exn.throw(dyn(IOError.from_errno(errno)))
|
|
166
156
|
)
|
|
167
157
|
}
|
|
168
158
|
)
|
|
169
159
|
})
|
|
170
160
|
);
|
|
171
|
-
|
|
172
161
|
/// Create a directory and all missing parents (`str` path variant).
|
|
173
|
-
create_dir_all_str :: (fn(path: str, using(io : IO)) -> Impl(Future(unit, IO, Exception)))(
|
|
162
|
+
create_dir_all_str :: (fn(path : str, using(io : IO)) -> Impl(Future(unit, IO, Exception)))(
|
|
174
163
|
create_dir_all(Path.new(String.from(path)))
|
|
175
164
|
);
|
|
176
|
-
|
|
177
165
|
/// Remove an empty directory. Throws if the directory is not empty.
|
|
178
|
-
remove_dir :: (fn(path: Path, using(io : IO)) -> Impl(Future(unit, IO, Exception)))(
|
|
166
|
+
remove_dir :: (fn(path : Path, using(io : IO)) -> Impl(Future(unit, IO, Exception)))(
|
|
179
167
|
io.async((using(io, exn)) => {
|
|
180
168
|
cstr_bytes := path.to_string().to_cstr();
|
|
181
169
|
cstr := cstr_bytes.ptr().unwrap();
|
|
182
170
|
result := io.await(IO_dir.unlink(AT_FDCWD, cstr, AT_REMOVEDIR));
|
|
183
171
|
cond(
|
|
184
|
-
(result < i32(0)) => exn.throw(dyn
|
|
172
|
+
(result < i32(0)) => exn.throw(dyn(IOError.from_errno(i32(0) - result))),
|
|
185
173
|
true => ()
|
|
186
174
|
)
|
|
187
175
|
})
|
|
188
176
|
);
|
|
189
|
-
|
|
190
|
-
remove_dir_str :: (fn(path: str, using(io : IO)) -> Impl(Future(unit, IO, Exception)))(
|
|
177
|
+
remove_dir_str :: (fn(path : str, using(io : IO)) -> Impl(Future(unit, IO, Exception)))(
|
|
191
178
|
remove_dir(Path.new(String.from(path)))
|
|
192
179
|
);
|
|
193
|
-
|
|
194
180
|
/// Remove a file at the given path.
|
|
195
|
-
remove_file :: (fn(path: Path, using(io : IO)) -> Impl(Future(unit, IO, Exception)))(
|
|
181
|
+
remove_file :: (fn(path : Path, using(io : IO)) -> Impl(Future(unit, IO, Exception)))(
|
|
196
182
|
io.async((using(io, exn)) => {
|
|
197
183
|
cstr_bytes := path.to_string().to_cstr();
|
|
198
184
|
cstr := cstr_bytes.ptr().unwrap();
|
|
199
185
|
result := io.await(IO_dir.unlink(AT_FDCWD, cstr, i32(0)));
|
|
200
186
|
cond(
|
|
201
|
-
(result < i32(0)) => exn.throw(dyn
|
|
187
|
+
(result < i32(0)) => exn.throw(dyn(IOError.from_errno(i32(0) - result))),
|
|
202
188
|
true => ()
|
|
203
189
|
)
|
|
204
190
|
})
|
|
205
191
|
);
|
|
206
|
-
|
|
207
|
-
remove_file_str :: (fn(path: str, using(io : IO)) -> Impl(Future(unit, IO, Exception)))
|
|
208
|
-
remove_file(Path.new(String.from(path)))
|
|
209
|
-
;
|
|
210
|
-
|
|
192
|
+
remove_file_str :: (fn(path : str, using(io : IO)) -> Impl(Future(unit, IO, Exception)))(remove_file(Path.new(String.from(path))));
|
|
211
193
|
/// Rename or move a file or directory from `from` to `to`.
|
|
212
|
-
rename :: (fn(from: Path, to: Path, using(io : IO)) -> Impl(Future(unit, IO, Exception)))(
|
|
194
|
+
rename :: (fn(from : Path, to : Path, using(io : IO)) -> Impl(Future(unit, IO, Exception)))(
|
|
213
195
|
io.async((using(io, exn)) => {
|
|
214
196
|
from_cstr_bytes := from.to_string().to_cstr();
|
|
215
197
|
from_cstr := from_cstr_bytes.ptr().unwrap();
|
|
@@ -217,18 +199,14 @@ rename :: (fn(from: Path, to: Path, using(io : IO)) -> Impl(Future(unit, IO, Exc
|
|
|
217
199
|
to_cstr := to_cstr_bytes.ptr().unwrap();
|
|
218
200
|
result := io.await(IO_dir.rename(AT_FDCWD, from_cstr, AT_FDCWD, to_cstr));
|
|
219
201
|
cond(
|
|
220
|
-
(result < i32(0)) => exn.throw(dyn
|
|
202
|
+
(result < i32(0)) => exn.throw(dyn(IOError.from_errno(i32(0) - result))),
|
|
221
203
|
true => ()
|
|
222
204
|
)
|
|
223
205
|
})
|
|
224
206
|
);
|
|
225
|
-
|
|
226
|
-
rename_str :: (fn(from: str, to: str, using(io : IO)) -> Impl(Future(unit, IO, Exception)))
|
|
227
|
-
rename(Path.new(String.from(from)), Path.new(String.from(to)))
|
|
228
|
-
;
|
|
229
|
-
|
|
207
|
+
rename_str :: (fn(from : str, to : str, using(io : IO)) -> Impl(Future(unit, IO, Exception)))(rename(Path.new(String.from(from)), Path.new(String.from(to))));
|
|
230
208
|
/// Create a hard link from `src` to `dst`.
|
|
231
|
-
hard_link :: (fn(src: Path, dst: Path, using(io : IO)) -> Impl(Future(unit, IO, Exception)))(
|
|
209
|
+
hard_link :: (fn(src : Path, dst : Path, using(io : IO)) -> Impl(Future(unit, IO, Exception)))(
|
|
232
210
|
io.async((using(io, exn)) => {
|
|
233
211
|
src_cstr_bytes := src.to_string().to_cstr();
|
|
234
212
|
src_cstr := src_cstr_bytes.ptr().unwrap();
|
|
@@ -236,18 +214,14 @@ hard_link :: (fn(src: Path, dst: Path, using(io : IO)) -> Impl(Future(unit, IO,
|
|
|
236
214
|
dst_cstr := dst_cstr_bytes.ptr().unwrap();
|
|
237
215
|
result := io.await(IO_dir.link(AT_FDCWD, src_cstr, AT_FDCWD, dst_cstr, i32(0)));
|
|
238
216
|
cond(
|
|
239
|
-
(result < i32(0)) => exn.throw(dyn
|
|
217
|
+
(result < i32(0)) => exn.throw(dyn(IOError.from_errno(i32(0) - result))),
|
|
240
218
|
true => ()
|
|
241
219
|
)
|
|
242
220
|
})
|
|
243
221
|
);
|
|
244
|
-
|
|
245
|
-
hard_link_str :: (fn(src: str, dst: str, using(io : IO)) -> Impl(Future(unit, IO, Exception)))
|
|
246
|
-
hard_link(Path.new(String.from(src)), Path.new(String.from(dst)))
|
|
247
|
-
;
|
|
248
|
-
|
|
222
|
+
hard_link_str :: (fn(src : str, dst : str, using(io : IO)) -> Impl(Future(unit, IO, Exception)))(hard_link(Path.new(String.from(src)), Path.new(String.from(dst))));
|
|
249
223
|
/// Create a symbolic link at `dst` pointing to `src`.
|
|
250
|
-
symlink :: (fn(src: Path, dst: Path, using(io : IO)) -> Impl(Future(unit, IO, Exception)))(
|
|
224
|
+
symlink :: (fn(src : Path, dst : Path, using(io : IO)) -> Impl(Future(unit, IO, Exception)))(
|
|
251
225
|
io.async((using(io, exn)) => {
|
|
252
226
|
src_cstr_bytes := src.to_string().to_cstr();
|
|
253
227
|
src_cstr := src_cstr_bytes.ptr().unwrap();
|
|
@@ -255,48 +229,45 @@ symlink :: (fn(src: Path, dst: Path, using(io : IO)) -> Impl(Future(unit, IO, Ex
|
|
|
255
229
|
dst_cstr := dst_cstr_bytes.ptr().unwrap();
|
|
256
230
|
result := io.await(IO_dir.symlink(src_cstr, AT_FDCWD, dst_cstr));
|
|
257
231
|
cond(
|
|
258
|
-
(result < i32(0)) => exn.throw(dyn
|
|
232
|
+
(result < i32(0)) => exn.throw(dyn(IOError.from_errno(i32(0) - result))),
|
|
259
233
|
true => ()
|
|
260
234
|
)
|
|
261
235
|
})
|
|
262
236
|
);
|
|
263
|
-
|
|
264
|
-
symlink_str :: (fn(src: str, dst: str, using(io : IO)) -> Impl(Future(unit, IO, Exception)))
|
|
265
|
-
symlink(Path.new(String.from(src)), Path.new(String.from(dst)))
|
|
266
|
-
;
|
|
267
|
-
|
|
237
|
+
symlink_str :: (fn(src : str, dst : str, using(io : IO)) -> Impl(Future(unit, IO, Exception)))(symlink(Path.new(String.from(src)), Path.new(String.from(dst))));
|
|
268
238
|
// ============================================================================
|
|
269
239
|
// Directory listing
|
|
270
240
|
// ============================================================================
|
|
271
|
-
|
|
272
241
|
/// Read all entries from a directory, returning an `ArrayList(DirEntry)`.
|
|
273
242
|
/// Skips the `.` and `..` entries.
|
|
274
|
-
read_dir :: (fn(path: Path, using(io : IO)) -> Impl(Future(ArrayList(DirEntry), IO, Exception)))(
|
|
243
|
+
read_dir :: (fn(path : Path, using(io : IO)) -> Impl(Future(ArrayList(DirEntry), IO, Exception)))(
|
|
275
244
|
io.async((using(io, exn)) => {
|
|
276
245
|
cstr_bytes := path.to_string().to_cstr();
|
|
277
246
|
cstr := cstr_bytes.ptr().unwrap();
|
|
278
247
|
// Open the directory
|
|
279
|
-
fd_result := io.await(IO_file.openat(AT_FDCWD, cstr,
|
|
248
|
+
fd_result := io.await(IO_file.openat(AT_FDCWD, cstr, O_RDONLY | O_DIRECTORY, i32(0)));
|
|
280
249
|
cond(
|
|
281
|
-
(fd_result < i32(0)) => exn.throw(dyn
|
|
250
|
+
(fd_result < i32(0)) => exn.throw(dyn(IOError.from_errno(i32(0) - fd_result))),
|
|
282
251
|
true => ()
|
|
283
252
|
);
|
|
284
253
|
fd := fd_result;
|
|
285
254
|
entries := ArrayList(DirEntry).new();
|
|
286
255
|
buf_size := u32(4096);
|
|
287
256
|
buf := *(u8)(malloc(usize(buf_size)).unwrap());
|
|
288
|
-
while
|
|
257
|
+
while(runtime(true), {
|
|
289
258
|
n := io.await(IO_dir.getdents(fd, buf, buf_size));
|
|
290
259
|
cond(
|
|
291
260
|
(n < i32(0)) => {
|
|
292
261
|
free(.Some(*(void)(buf)));
|
|
293
262
|
io.await(IO_file.close(fd));
|
|
294
|
-
exn.throw(dyn
|
|
263
|
+
exn.throw(dyn(IOError.from_errno(i32(0) - n)));
|
|
264
|
+
},
|
|
265
|
+
(n == i32(0)) => {
|
|
266
|
+
break;
|
|
295
267
|
},
|
|
296
|
-
(n == i32(0)) => { break; },
|
|
297
268
|
true => {
|
|
298
269
|
offset := usize(0);
|
|
299
|
-
while
|
|
270
|
+
while(runtime(offset < usize(n)), {
|
|
300
271
|
entry_ptr := (buf &+ offset);
|
|
301
272
|
name_ptr := IO_dir.dirent_name(entry_ptr);
|
|
302
273
|
name := String.from_cstr(name_ptr).unwrap();
|
|
@@ -311,31 +282,41 @@ read_dir :: (fn(path: Path, using(io : IO)) -> Impl(Future(ArrayList(DirEntry),
|
|
|
311
282
|
(dt == DT_LNK) => FileType.Symlink,
|
|
312
283
|
true => FileType.Other
|
|
313
284
|
);
|
|
314
|
-
entries.push(
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
285
|
+
entries.push(
|
|
286
|
+
DirEntry(
|
|
287
|
+
name : name,
|
|
288
|
+
file_type : ft,
|
|
289
|
+
ino : IO_dir.dirent_ino(entry_ptr)
|
|
290
|
+
)
|
|
291
|
+
);
|
|
319
292
|
}
|
|
320
293
|
);
|
|
321
294
|
offset = (offset + usize(IO_dir.dirent_reclen(entry_ptr)));
|
|
322
|
-
};
|
|
295
|
+
});
|
|
323
296
|
}
|
|
324
297
|
);
|
|
325
|
-
};
|
|
298
|
+
});
|
|
326
299
|
free(.Some(*(void)(buf)));
|
|
327
300
|
io.await(IO_file.close(fd));
|
|
328
301
|
entries
|
|
329
302
|
})
|
|
330
303
|
);
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
304
|
+
read_dir_str :: (fn(path : str, using(io : IO)) -> Impl(Future(ArrayList(DirEntry), IO, Exception)))(read_dir(Path.new(String.from(path))));
|
|
305
|
+
export(
|
|
306
|
+
create_dir,
|
|
307
|
+
create_dir_str,
|
|
308
|
+
create_dir_all,
|
|
309
|
+
create_dir_all_str,
|
|
310
|
+
remove_dir,
|
|
311
|
+
remove_dir_str,
|
|
312
|
+
remove_file,
|
|
313
|
+
remove_file_str,
|
|
314
|
+
rename,
|
|
315
|
+
rename_str,
|
|
316
|
+
hard_link,
|
|
317
|
+
hard_link_str,
|
|
318
|
+
symlink,
|
|
319
|
+
symlink_str,
|
|
320
|
+
read_dir,
|
|
321
|
+
read_dir_str
|
|
322
|
+
);
|