diff --git a/composer.json b/composer.json index d6aec63..1ba811b 100644 --- a/composer.json +++ b/composer.json @@ -21,12 +21,11 @@ "minimum-stability": "dev", "prefer-stable": true, "require": { - "php": ">=5.5", "amphp/amp": "dev-master as 2.0" }, "require-dev": { "amphp/loop": "dev-master", - "phpunit/phpunit": "^4|^5", + "phpunit/phpunit": "^5", "friendsofphp/php-cs-fixer": "~1.9" }, "autoload": { diff --git a/lib/Buffer.php b/lib/Buffer.php index 62e3530..42fa545 100644 --- a/lib/Buffer.php +++ b/lib/Buffer.php @@ -14,8 +14,8 @@ class Buffer implements \ArrayAccess, \Countable, \IteratorAggregate * * @param string $data */ - public function __construct($data = '') { - $this->data = (string) $data; + public function __construct(string $data = '') { + $this->data = $data; } /** @@ -23,14 +23,14 @@ class Buffer implements \ArrayAccess, \Countable, \IteratorAggregate * * @return int */ - public function getLength() { + public function getLength(): int { return \strlen($this->data); } /** * @return int */ - public function count() { + public function count(): int { return $this->getLength(); } @@ -39,7 +39,7 @@ class Buffer implements \ArrayAccess, \Countable, \IteratorAggregate * * @return bool */ - public function isEmpty() { + public function isEmpty(): bool { return $this->data === ''; } @@ -48,7 +48,7 @@ class Buffer implements \ArrayAccess, \Countable, \IteratorAggregate * * @param string $data */ - public function push($data) { + public function push(string $data) { $this->data .= $data; } @@ -57,7 +57,7 @@ class Buffer implements \ArrayAccess, \Countable, \IteratorAggregate * * @param string $data */ - public function unshift($data) { + public function unshift(string $data): string { $this->data = $data . $this->data; } @@ -66,8 +66,7 @@ class Buffer implements \ArrayAccess, \Countable, \IteratorAggregate * * @return string */ - public function shift($length) { - $length = (int) $length; + public function shift(int $length): string { if ($length <= 0) { return ''; } @@ -92,13 +91,11 @@ class Buffer implements \ArrayAccess, \Countable, \IteratorAggregate * * @return string */ - public function peek($length, $offset = 0) { - $length = (int) $length; + public function peek(int $length, int $offset = 0): string { if ($length <= 0) { return ''; } - $offset = (int) $offset; if ($offset < 0) { $offset = 0; } @@ -115,8 +112,7 @@ class Buffer implements \ArrayAccess, \Countable, \IteratorAggregate * * @return string */ - public function pop($length) { - $length = (int) $length; + public function pop(int $length): string { if ($length <= 0) { return ''; } @@ -136,13 +132,11 @@ class Buffer implements \ArrayAccess, \Countable, \IteratorAggregate * * @return string */ - public function remove($length, $offset = 0) { - $length = (int) $length; + public function remove(int $length, int $offset = 0): string { if ($length <= 0) { return ''; } - $offset = (int) $offset; if ($offset < 0) { $offset = 0; } @@ -163,7 +157,7 @@ class Buffer implements \ArrayAccess, \Countable, \IteratorAggregate * * @return string */ - public function drain() { + public function drain(): string { $buffer = $this->data; $this->data = ''; return $buffer; @@ -175,7 +169,7 @@ class Buffer implements \ArrayAccess, \Countable, \IteratorAggregate * @param string $string * @param int $position */ - public function insert($string, $position) { + public function insert(string $string, int $position) { $this->data = \substr_replace($this->data, $string, $position, 0); } @@ -187,7 +181,7 @@ class Buffer implements \ArrayAccess, \Countable, \IteratorAggregate * * @return int Number of replacements performed. */ - public function replace($search, $replace) { + public function replace($search, $replace): int { $this->data = \str_replace($search, $replace, $this->data, $count); return $count; } @@ -202,7 +196,7 @@ class Buffer implements \ArrayAccess, \Countable, \IteratorAggregate * * @see strpos() */ - public function search($string, $reverse = false) { + public function search(string $string, bool $reverse = false) { if ($reverse) { return \strrpos($this->data, $string); } @@ -256,14 +250,14 @@ class Buffer implements \ArrayAccess, \Countable, \IteratorAggregate /** * @return BufferIterator */ - public function getIterator() { + public function getIterator(): \Iterator { return new BufferIterator($this); } /** * @return string */ - public function __toString() { + public function __toString(): string { return $this->data; } } diff --git a/lib/BufferIterator.php b/lib/BufferIterator.php index feb67b0..08d89c3 100644 --- a/lib/BufferIterator.php +++ b/lib/BufferIterator.php @@ -6,14 +6,10 @@ namespace Amp\Stream; */ class BufferIterator implements \SeekableIterator { - /** - * @var Buffer - */ + /** @var \Amp\Stream\Buffer */ private $buffer; - /** - * @var int - */ + /** @var int */ private $current = 0; /** @@ -35,7 +31,7 @@ class BufferIterator implements \SeekableIterator * * @return bool */ - public function valid() { + public function valid(): bool { return isset($this->buffer[$this->current]); } @@ -44,7 +40,7 @@ class BufferIterator implements \SeekableIterator * * @return int */ - public function key() { + public function key(): int { return $this->current; } @@ -53,7 +49,7 @@ class BufferIterator implements \SeekableIterator * * @return string */ - public function current() { + public function current(): string { return $this->buffer[$this->current]; } @@ -93,7 +89,7 @@ class BufferIterator implements \SeekableIterator * * @throws \OutOfBoundsException If the iterator is invalid. */ - public function insert($data) { + public function insert(string $data) { if (!$this->valid()) { throw new \OutOfBoundsException('The iterator is not valid!'); } @@ -110,7 +106,7 @@ class BufferIterator implements \SeekableIterator * * @throws \OutOfBoundsException If the iterator is invalid. */ - public function replace($data) { + public function replace(string $data): string { if (!$this->valid()) { throw new \OutOfBoundsException('The iterator is not valid!'); } @@ -129,7 +125,7 @@ class BufferIterator implements \SeekableIterator * * @throws \OutOfBoundsException If the iterator is invalid. */ - public function remove() { + public function remove(): string { if (!$this->valid()) { throw new \OutOfBoundsException('The iterator is not valid!'); } diff --git a/lib/ClosedException.php b/lib/ClosedException.php index 71acbf4..62ac520 100644 --- a/lib/ClosedException.php +++ b/lib/ClosedException.php @@ -2,4 +2,4 @@ namespace Amp\Stream; -class ClosedException extends \RuntimeException {} +class ClosedException extends \Exception {} diff --git a/lib/MemoryStream.php b/lib/MemoryStream.php index 405ad1e..bd6ffc1 100644 --- a/lib/MemoryStream.php +++ b/lib/MemoryStream.php @@ -2,9 +2,8 @@ namespace Amp\Stream; -use Amp\Deferred; -use Amp\Failure; -use Amp\Success; +use Amp\{ Deferred, Failure, Success }; +use Interop\Async\Awaitable; /** * Serves as buffer that implements the stream interface, allowing consumers to be notified when data is available in @@ -27,7 +26,7 @@ class MemoryStream implements Stream { /** * @param string $data */ - public function __construct($data = '') { + public function __construct(string $data = '') { $this->buffer = new Buffer($data); $this->reads = new \SplQueue; } @@ -35,14 +34,14 @@ class MemoryStream implements Stream { /** * {@inheritdoc} */ - public function isReadable() { + public function isReadable(): bool { return $this->readable; } /** * {@inheritdoc} */ - public function isWritable() { + public function isWritable(): bool { return $this->writable; } @@ -66,12 +65,9 @@ class MemoryStream implements Stream { /** * {@inheritdoc} */ - public function read($bytes = null, $delimiter = null) { - if ($bytes !== null) { - $bytes = (int) $bytes; - if ($bytes <= 0) { - throw new \InvalidArgumentException("The number of bytes to read should be a positive integer or null"); - } + public function read(int $bytes = null, string $delimiter = null): Awaitable { + if ($bytes !== null && $bytes <= 0) { + throw new \InvalidArgumentException("The number of bytes to read should be a positive integer or null"); } if (!$this->readable) { @@ -119,19 +115,23 @@ class MemoryStream implements Stream { $this->reads->unshift([$bytes, $delimiter, $deferred]); return; } + + if (!$this->writable && $this->buffer->isEmpty()) { + $this->close(); + } } /** * {@inheritdoc} */ - public function write($data) { + public function write(string $data): Awaitable { return $this->send($data, false); } /** * {@inheritdoc} */ - public function end($data = '') { + public function end(string $data = ''): Awaitable { return $this->send($data, true); } @@ -141,7 +141,7 @@ class MemoryStream implements Stream { * * @return \Interop\Async\Awaitable */ - protected function send($data, $end = false) { + protected function send(string $data, bool $end = false): Awaitable { if (!$this->writable) { return new Failure(new \LogicException("The stream is not writable")); } diff --git a/lib/Stream.php b/lib/Stream.php index aa9e336..0be2141 100644 --- a/lib/Stream.php +++ b/lib/Stream.php @@ -2,20 +2,22 @@ namespace Amp\Stream; +use Interop\Async\Awaitable; + interface Stream { /** * Determines if the stream is readable. * * @return bool */ - public function isReadable(); + public function isReadable(): bool; /** * Determines if the stream is writable. * * @return bool */ - public function isWritable(); + public function isWritable(): bool; /** * @param int|null $bytes @@ -23,21 +25,21 @@ interface Stream { * * @return \Interop\Async\Awaitable Resolves with bytes read from the stream. */ - public function read($bytes = null, $delimiter = null); + public function read(int $bytes = null, string $delimiter = null): Awaitable; /** * @param string $data * * @return \Interop\Async\Awaitable */ - public function write($data); + public function write(string $data): Awaitable; /** * @param string $data * * @return \Interop\Async\Awaitable */ - public function end($data = ''); + public function end(string $data = ''): Awaitable; /** * Closes the stream and fails any pending reads or writes. diff --git a/lib/functions.php b/lib/functions.php index 0499cb6..10d2f8f 100644 --- a/lib/functions.php +++ b/lib/functions.php @@ -3,10 +3,11 @@ namespace Amp\Stream; use Amp\Coroutine; +use Interop\Async\Awaitable; // @codeCoverageIgnoreStart if (\strlen('…') !== 3) { - throw new \RuntimeException( + throw new \Error( 'The mbstring.func_overload ini setting is enabled. It must be disable to use the stream package.' ); } // @codeCoverageIgnoreEnd @@ -18,31 +19,28 @@ if (\strlen('…') !== 3) { * * @return \Interop\Async\Awaitable */ -function pipe(Stream $source, Stream $destination, $bytes = null) { +function pipe(Stream $source, Stream $destination, int $bytes = null): Awaitable { return new Coroutine(__doPipe($source, $destination, $bytes)); } -function __doPipe(Stream $source, Stream $destination, $bytes = null) { +function __doPipe(Stream $source, Stream $destination, int $bytes = null): \Generator { if (!$destination->isWritable()) { throw new \LogicException("The destination is not writable"); } if (null !== $bytes) { - yield Coroutine::result( - yield $destination->write( - yield $source->read($bytes) - ) + return yield $destination->write( + yield $source->read($bytes) ); - return; } $written = 0; do { - $written += (yield $destination->write( + $written += yield $destination->write( yield $source->read() - )); + ); } while ($source->isReadable() && $destination->isWritable()); - yield Coroutine::result($written); + return $written; }