Skip to content

Commit

Permalink
[0.2.x] Improve file read/write tests
Browse files Browse the repository at this point in the history
  • Loading branch information
WyriHaximus committed Jun 2, 2023
1 parent ca5e06f commit 13708a5
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 43 deletions.
46 changes: 23 additions & 23 deletions src/Eio/File.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

final class File implements FileInterface
{
private const READ_CHUNK_FIZE = 65536;

use StatTrait;

private PollInterface $poll;
Expand Down Expand Up @@ -37,22 +39,29 @@ public function getContents(int $offset = 0 , ?int $maxlen = null): PromiseInter
0,
)->then(
function ($fileDescriptor) use ($offset, $maxlen): PromiseInterface {
if ($maxlen === null) {
$sizePromise = $this->statFileDescriptor($fileDescriptor)->then(static function ($stat): int {
return (int)$stat['size'];
});
} else {
$sizePromise = resolve($maxlen);
}
return $sizePromise->then(function ($length) use ($fileDescriptor, $offset): PromiseInterface {
return new Promise (function (callable $resolve) use ($fileDescriptor, $offset, $length): void {
\eio_read($fileDescriptor, $length, $offset, \EIO_PRI_DEFAULT, function ($fileDescriptor, string $buffer) use ($resolve): void {
$resolve($this->closeOpenFile($fileDescriptor)->then(function () use ($buffer): string {
return $buffer;
}));
$buffer = '';
$read = function () use ($fileDescriptor, $offset, $maxlen, &$read, &$buffer) {
return new Promise (function (callable $resolve) use ($fileDescriptor, $offset, $maxlen, &$read, &$buffer): void {
\eio_read($fileDescriptor, $maxlen ?? self::READ_CHUNK_FIZE, $offset, \PHP_INT_MAX, function ($fileDescriptor, string $contents) use ($resolve, $maxlen, &$read, &$buffer): void {
$buffer .= $contents;
$bufferLength = strlen($buffer);

if ($maxlen === null || $bufferLength >= $maxlen) {
if ($maxlen !== null && $bufferLength > $maxlen) {
$buffer = substr($buffer, 0, $maxlen);
}

$resolve($this->closeOpenFile($fileDescriptor)->then(function () use ($buffer): string {
return $buffer;
}));
} else {
$read();
}
}, $fileDescriptor);
});
});
};

return $read();
}
);
}
Expand All @@ -77,15 +86,6 @@ function ($fileDescriptor) use ($contents, $flags): PromiseInterface {
);
}

private function statFileDescriptor($fileDescriptor): PromiseInterface
{
return new Promise(function (callable $resolve, callable $reject) use ($fileDescriptor) {
\eio_fstat($fileDescriptor, \EIO_PRI_DEFAULT, function ($_, $stat) use ($resolve): void {
$resolve($stat);
}, $fileDescriptor);
});
}

private function openFile(string $path, int $flags, int $mode): PromiseInterface
{
return new Promise(function (callable $resolve, callable $reject) use ($path, $flags, $mode): void {
Expand Down
2 changes: 1 addition & 1 deletion src/Fallback/File.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public function stat(): PromiseInterface
public function getContents(int $offset = 0 , ?int $maxlen = null): PromiseInterface
{
$path = $this->path . $this->name;
return resolve(file_get_contents($path, false, null, $offset, $maxlen ?? (int)stat($path)['size']));
return resolve(file_get_contents($path, false, null, $offset, $maxlen));
}

public function putContents(string $contents, int $flags = 0): PromiseInterface
Expand Down
87 changes: 68 additions & 19 deletions src/Uv/File.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@

final class File implements FileInterface
{
private const READ_CHUNK_FIZE = 65536;

use StatTrait;

private ExtUvLoop $loop;
Expand All @@ -36,41 +38,88 @@ public function stat(): PromiseInterface
public function getContents(int $offset = 0 , ?int $maxlen = null): PromiseInterface
{
$this->activate();
return new Promise(function (callable $resolve) use ($offset, $maxlen): void {
uv_fs_open($this->uvLoop, $this->path . DIRECTORY_SEPARATOR . $this->name, UV::O_RDONLY, 0, function ($fileDescriptor) use ($resolve, $offset, $maxlen): void {
uv_fs_fstat($this->uvLoop, $fileDescriptor, function ($fileDescriptor, array $stat) use ($resolve, $offset, $maxlen): void {
uv_fs_read($this->uvLoop, $fileDescriptor, $offset, $maxlen ?? (int)$stat['size'], function ($fileDescriptor, string $buffer) use ($resolve): void {
$resolve($buffer);
uv_fs_close($this->uvLoop, $fileDescriptor, function () {
$this->deactivate();
return $this->openFile(
$this->path . DIRECTORY_SEPARATOR . $this->name,
UV::O_RDONLY,
0,
)->then(
function ($fileDescriptor) use ($offset, $maxlen): PromiseInterface {
$buffer = '';
$read = function () use ($fileDescriptor, $offset, $maxlen, &$read, &$buffer) {
return new Promise (function (callable $resolve) use ($fileDescriptor, $offset, $maxlen, &$read, &$buffer): void {
uv_fs_read($this->uvLoop, $fileDescriptor, $offset, $maxlen ?? self::READ_CHUNK_FIZE, function ($fileDescriptor, string $contents) use ($resolve, $maxlen, &$read, &$buffer): void {
$buffer .= $contents;
$bufferLength = strlen($buffer);

if ($maxlen === null || $bufferLength >= $maxlen) {
if ($maxlen !== null && $bufferLength > $maxlen) {
$buffer = substr($buffer, 0, $maxlen);
}

$resolve($this->closeOpenFile($fileDescriptor)->then(function () use ($buffer): string {
return $buffer;
}));
} else {
$read();
}
});
});
});
});
};

return $read();
});
}

public function putContents(string $contents, int $flags = 0)
{
$this->activate();
return new Promise(function (callable $resolve) use ($contents, $flags): void {
return $this->openFile(
$this->path . DIRECTORY_SEPARATOR . $this->name,
(($flags & \FILE_APPEND) == \FILE_APPEND) ? UV::O_RDWR | UV::O_CREAT | UV::O_APPEND : UV::O_RDWR | UV::O_CREAT,
0644,
)->then(
function ($fileDescriptor) use ($contents): PromiseInterface {
return new Promise (function (callable $resolve) use ($contents, $fileDescriptor): void {
uv_fs_write($this->uvLoop, $fileDescriptor, $contents, 0, function ($fileDescriptor, int $bytesWritten) use ($resolve): void {
$resolve($this->closeOpenFile($fileDescriptor)->then(function () use ($bytesWritten): int {
return $bytesWritten;
}));
});
}
);
});
}

private function openFile(string $path, int $flags, int $mode): PromiseInterface
{
return new Promise(function (callable $resolve) use ($path, $flags, $mode): void {
uv_fs_open(
$this->uvLoop,
$this->path . DIRECTORY_SEPARATOR . $this->name,
(($flags & \FILE_APPEND) == \FILE_APPEND) ? UV::O_RDWR | UV::O_CREAT | UV::O_APPEND : UV::O_RDWR | UV::O_CREAT,
0644,
function ($fileDescriptor) use ($resolve, $contents, $flags): void {
uv_fs_write($this->uvLoop, $fileDescriptor, $contents, 0, function ($fileDescriptor, int $bytesWritten) use ($resolve): void {
$resolve($bytesWritten);
uv_fs_close($this->uvLoop, $fileDescriptor, function () {
$this->deactivate();
});
});
$flags,
$mode,
function ($fileDescriptor) use ($resolve): void {
$resolve($fileDescriptor);
}
);
});
}

private function closeOpenFile($fileDescriptor): PromiseInterface
{
return new Promise(function (callable $resolve) use ($fileDescriptor) {
try {
uv_fs_close($this->uvLoop, $fileDescriptor, function () use ($resolve) {
$this->deactivate();
$resolve();
});
} catch (\Throwable $error) {
$this->deactivate();
throw $error;
}
});
}

public function unlink(): PromiseInterface
{
$this->activate();
Expand Down
14 changes: 14 additions & 0 deletions tests/FileTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,20 @@ public function getContents(AdapterInterface $filesystem): void
self::assertSame(file_get_contents(__FILE__), $fileContents);
}

/**
* @test
*
* @dataProvider provideFilesystems
*/
public function getContentsWithFilesize(AdapterInterface $filesystem): void
{
$fileContents = await($filesystem->detect(__FILE__)->then(static function (FileInterface $file): PromiseInterface {
return $file->getContents(0, filesize(__FILE__));
}));

self::assertSame(file_get_contents(__FILE__), $fileContents);
}

/**
* @test
*
Expand Down

0 comments on commit 13708a5

Please sign in to comment.