A file handle is stateful and must not be used concurrently.
| 182 | |
| 183 | /** A file handle is stateful and must not be used concurrently. */ |
| 184 | class FileImpl implements FileSystem.File { |
| 185 | readonly [FileSystem.FileTypeId]: typeof FileSystem.FileTypeId = FileSystem.FileTypeId |
| 186 | private readonly file: Deno.FsFile |
| 187 | private readonly append: boolean |
| 188 | private position = BigInt(0) |
| 189 | private nativePosition: bigint | undefined = undefined |
| 190 | |
| 191 | constructor( |
| 192 | file: Deno.FsFile, |
| 193 | append: boolean |
| 194 | ) { |
| 195 | this.file = file |
| 196 | this.append = append |
| 197 | } |
| 198 | |
| 199 | get stat() { |
| 200 | return Effect.map( |
| 201 | tryPromise("stat", undefined, () => this.file.stat()), |
| 202 | makeFileInfo |
| 203 | ) |
| 204 | } |
| 205 | |
| 206 | get sync() { |
| 207 | return tryPromise("sync", undefined, () => this.file.sync()) |
| 208 | } |
| 209 | |
| 210 | seek(offset: FileSystem.SizeInput, from: FileSystem.SeekMode) { |
| 211 | const size = FileSystem.Size(offset) |
| 212 | return Effect.sync(() => { |
| 213 | if (from === "start") { |
| 214 | this.position = size |
| 215 | } else { |
| 216 | this.position += size |
| 217 | } |
| 218 | return FileSystem.Size(this.position) |
| 219 | }) |
| 220 | } |
| 221 | |
| 222 | private readChunk(method: string, buffer: Uint8Array) { |
| 223 | return Effect.suspend(() => { |
| 224 | const position = this.position |
| 225 | return Effect.map( |
| 226 | tryPromise( |
| 227 | method, |
| 228 | undefined, |
| 229 | async () => { |
| 230 | if (this.nativePosition !== position) { |
| 231 | this.file.seekSync(position, Deno.SeekMode.Start) |
| 232 | } |
| 233 | this.nativePosition = undefined |
| 234 | return await this.file.read(buffer) |
| 235 | } |
| 236 | ), |
| 237 | (bytesRead) => { |
| 238 | const sizeRead = FileSystem.Size(bytesRead ?? 0) |
| 239 | this.position = this.nativePosition = position + sizeRead |
| 240 | return sizeRead |
| 241 | } |