@@ -6,35 +6,13 @@ import io
6
6
import io/error
7
7
8
8
9
- /// Represents the file opening modes with their respective flags
10
- /// Backends rely on the order of these
11
- type Mode {
12
- // Most common modes
13
- ReadOnly() // 'r' exception if does not exist
14
- WriteOnly() // 'w' created if does not exist, truncated if exists
15
- AppendOnly() // 'a' created if does not exist
16
-
17
- // Other modes
18
- ReadWrite() // 'w+' created if does not exist, truncated if exists
19
- ReadAppend() // 'a+' created if does not exist
20
- AppendExclusive() // 'ax' created if does not exist, fails if exists
21
- ReadAppendExclusive() // 'ax+' created if does not exist, fails if exists
22
- AppendSync() // 'as' created if does not exist, append in synchronous mode
23
- ReadAppendSync() // 'as+' created if does not exist, append in synchronous mode
24
- ReadSync() // 'rs' exception if does not exist, read in synchronous mode
25
- ReadWriteSync() // 'rs+' exception if does not exist, read/write in synchronous mode
26
- WriteExclusive() // 'wx' created if does not exist, truncated if exists, fails if exists
27
- ReadWriteExclusive() // 'wx+' created if does not exist, truncated if exists, fails if exists
28
- }
29
-
30
-
31
9
/// A file descriptor. Should not be inspected.
32
10
type File = Int
33
11
34
12
35
13
/// Reads a file at given path as utf8 encoded string.
36
14
def readFile(path: String): String / Exception[IOError] = {
37
- val file = open (path, ReadOnly() );
15
+ val file = openForReading (path);
38
16
with on[IOError].finalize { close(file) }
39
17
40
18
val chunkSize = 1048576 // 1MB
@@ -59,7 +37,7 @@ def readFile(path: String): String / Exception[IOError] = {
59
37
60
38
/// Writes the (utf8 encoded) string `contents` into the specified file.
61
39
def writeFile(path: String, contents: String): Unit / Exception[IOError] = {
62
- val file = open (path, WriteOnly() );
40
+ val file = openForWriting (path);
63
41
with on[IOError].finalize { close(file) }
64
42
65
43
val chunkSize = 1048576 // 1MB
@@ -75,6 +53,23 @@ def writeFile(path: String, contents: String): Unit / Exception[IOError] = {
75
53
go()
76
54
}
77
55
56
+ /// Appends the (utf8 encoded) string `contents` to the specified file.
57
+ def appendFile(path: String, contents: String): Unit / Exception[IOError] = {
58
+ val file = openForAppending(path);
59
+ with on[IOError].finalize { close(file) }
60
+
61
+ val chunkSize = 1048576 // 1MB
62
+ val buffer = contents.fromString
63
+ var offset = 0;
64
+
65
+ def go(): Unit = {
66
+ val n = write(file, buffer, offset, min(buffer.size - offset, chunkSize), -1)
67
+ offset = offset + n
68
+ if (offset < buffer.size) { go() }
69
+ }
70
+
71
+ go()
72
+ }
78
73
79
74
/// An abstract interface applications can program against.
80
75
///
@@ -95,8 +90,14 @@ def filesystem[R] { program: => R / Files }: R / Exception[IOError] = // TODO mo
95
90
}
96
91
97
92
98
- def open(path: String, mode: Mode): File / Exception[IOError] =
99
- internal::checkResult(internal::open(path, mode))
93
+ def openForReading(path: String): File / Exception[IOError] =
94
+ internal::checkResult(internal::openForReading(path))
95
+
96
+ def openForWriting(path: String): File / Exception[IOError] =
97
+ internal::checkResult(internal::openForWriting(path))
98
+
99
+ def openForAppending(path: String): File / Exception[IOError] =
100
+ internal::checkResult(internal::openForAppending(path))
100
101
101
102
def read(file: File, buffer: ByteArray, offset: Int, size: Int, position: Int): Int / Exception[IOError] =
102
103
internal::checkResult(internal::read(file, buffer, offset, size, position))
@@ -111,40 +112,6 @@ def close(file: File): Unit / Exception[IOError] = {
111
112
namespace internal {
112
113
113
114
extern js """
114
- function modeName(mode) {
115
- switch (mode.__tag) {
116
- case 0: // ReadOnly()
117
- return 'r';
118
- case 1: // WriteOnly()
119
- return 'w';
120
- case 2: // AppendOnly()
121
- return 'a';
122
- case 3: // ReadWrite()
123
- return 'w+';
124
- case 4: // ReadAppend()
125
- return 'a+';
126
- case 5: // AppendExclusive()
127
- return 'ax';
128
- case 6: // ReadAppendExclusive()
129
- return 'ax+';
130
- case 7: // AppendSync()
131
- return 'as';
132
- case 8: // ReadAppendSync()
133
- return 'as+';
134
- case 9: // ReadSync()
135
- return 'rs';
136
- case 10: // ReadWriteSync()
137
- return 'rs+';
138
- case 11: // WriteExclusive()
139
- return 'wx';
140
- case 12: // ReadWriteExclusive()
141
- return 'wx+';
142
- default:
143
- // Invalid tag value
144
- return null;
145
- }
146
- }
147
-
148
115
/**
149
116
* Nodejs file operations expect buffers, but we represent buffers as typed arrays.
150
117
* This function converts between the two without copying.
@@ -157,8 +124,8 @@ namespace internal {
157
124
extern jsNode """
158
125
const fs = require("fs");
159
126
160
- function open(path, mode , callback) {
161
- fs.open(path, modeName(mode) , (err, file) => {
127
+ function open(path, flags , callback) {
128
+ fs.open(path, flags , (err, file) => {
162
129
if (err) { callback(err.errno) } else { callback(file) }
163
130
})
164
131
}
@@ -185,16 +152,32 @@ namespace internal {
185
152
"""
186
153
187
154
extern llvm """
188
- declare void @c_fs_open(%Pos, %Pos, %Stack)
155
+ declare void @c_fs_open_reading(%Pos, %Stack)
156
+ declare void @c_fs_open_writing(%Pos, %Stack)
157
+ declare void @c_fs_open_appending(%Pos, %Stack)
189
158
declare void @c_fs_read(%Int, %Pos, %Int, %Int, %Int, %Stack)
190
159
declare void @c_fs_write(%Int, %Pos, %Int, %Int, %Int, %Stack)
191
160
declare void @c_fs_close(%Int, %Stack)
192
161
"""
193
162
194
- extern async def open(path: String, mode: Mode): Int =
195
- jsNode "$effekt.capture(callback => open(${path}, ${mode}, callback))"
163
+ extern async def openForReading(path: String): Int =
164
+ jsNode "$effekt.capture(callback => open(${path}, 'r', callback))"
165
+ llvm """
166
+ call void @c_fs_open_reading(%Pos ${path}, %Stack %stack)
167
+ ret void
168
+ """
169
+
170
+ extern async def openForWriting(path: String): Int =
171
+ jsNode "$effekt.capture(callback => open(${path}, 'w', callback))"
172
+ llvm """
173
+ call void @c_fs_open_writing(%Pos ${path}, %Stack %stack)
174
+ ret void
175
+ """
176
+
177
+ extern async def openForAppending(path: String): Int =
178
+ jsNode "$effekt.capture(callback => open(${path}, 'a', callback))"
196
179
llvm """
197
- call void @c_fs_open (%Pos ${path}, %Pos ${mode }, %Stack %stack)
180
+ call void @c_fs_open_appending (%Pos ${path}, %Stack %stack)
198
181
ret void
199
182
"""
200
183
0 commit comments