From 403abb88596818a26e2db613ca41609698972bd5 Mon Sep 17 00:00:00 2001 From: Andrea Marco Sartori Date: Sun, 22 Jan 2023 09:49:24 +1000 Subject: [PATCH] Implement progress --- src/JsonParser.php | 96 ++++++++++++++++++++++++-------------------- src/Lexer.php | 20 +++++++++- src/Parser.php | 10 +++++ src/Progress.php | 99 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 181 insertions(+), 44 deletions(-) create mode 100644 src/Progress.php diff --git a/src/JsonParser.php b/src/JsonParser.php index 625be22..96a5c1a 100644 --- a/src/JsonParser.php +++ b/src/JsonParser.php @@ -54,27 +54,13 @@ final class JsonParser implements IteratorAggregate } /** - * Set the simdjson decoder + * Retrieve the lazily iterable JSON * - * @param bool $decodesToArray - * @return static + * @return Traversable */ - public function simdjson(bool $decodesToArray = true): static + public function getIterator(): Traversable { - return $this->decoder(new SimdjsonDecoder($decodesToArray)); - } - - /** - * Set the JSON decoder - * - * @param Decoder $decoder - * @return static - */ - public function decoder(Decoder $decoder): static - { - $this->config->decoder = $decoder; - - return $this; + return $this->parser; } /** @@ -106,6 +92,55 @@ final class JsonParser implements IteratorAggregate return $this; } + /** + * Traverse the lazily iterable JSON + * + * @param Closure|null $callback + * @return void + */ + public function traverse(Closure $callback = null): void + { + $callback ??= fn () => true; + + foreach ($this as $key => $value) { + $callback($value, $key, $this); + } + } + + /** + * Set the simdjson decoder + * + * @param bool $decodesToArray + * @return static + */ + public function simdjson(bool $decodesToArray = true): static + { + return $this->decoder(new SimdjsonDecoder($decodesToArray)); + } + + /** + * Set the JSON decoder + * + * @param Decoder $decoder + * @return static + */ + public function decoder(Decoder $decoder): static + { + $this->config->decoder = $decoder; + + return $this; + } + + /** + * Retrieve the parsing progress + * + * @return Progress + */ + public function progress(): Progress + { + return $this->parser->progress(); + } + /** * The number of bytes to read in each chunk * @@ -141,29 +176,4 @@ final class JsonParser implements IteratorAggregate return $this; } - - /** - * Traverse the lazily iterable JSON - * - * @param Closure|null $callback - * @return void - */ - public function traverse(Closure $callback = null): void - { - $callback ??= fn () => true; - - foreach ($this as $key => $value) { - $callback($value, $key, $this); - } - } - - /** - * Retrieve the lazily iterable JSON - * - * @return Traversable - */ - public function getIterator(): Traversable - { - return $this->parser; - } } diff --git a/src/Lexer.php b/src/Lexer.php index dac4206..1fd54a6 100644 --- a/src/Lexer.php +++ b/src/Lexer.php @@ -17,6 +17,13 @@ use Traversable; */ final class Lexer implements IteratorAggregate { + /** + * The parsing progress. + * + * @var Progress + */ + private Progress $progress; + /** * The buffer to yield. * @@ -45,6 +52,7 @@ final class Lexer implements IteratorAggregate */ public function __construct(private Source $source) { + $this->progress = new Progress(); } /** @@ -55,7 +63,7 @@ final class Lexer implements IteratorAggregate public function getIterator(): Traversable { foreach ($this->source as $chunk) { - for ($i = 0, $size = strlen($chunk); $i < $size; $i++) { + for ($i = 0, $size = strlen($chunk); $i < $size; $i++, $this->progress->advance()) { $character = $chunk[$i]; $this->inString = $this->inString($character); $this->isEscaping = $character == '\\' && !$this->isEscaping; @@ -100,4 +108,14 @@ final class Lexer implements IteratorAggregate yield Tokenizer::instance()->toToken($character); } } + + /** + * Retrieve the parsing progress + * + * @return Progress + */ + public function progress(): Progress + { + return $this->progress->setTotal($this->source->size()); + } } diff --git a/src/Parser.php b/src/Parser.php index 869ab84..37e76ad 100644 --- a/src/Parser.php +++ b/src/Parser.php @@ -80,4 +80,14 @@ final class Parser implements IteratorAggregate } } } + + /** + * Retrieve the parsing progress + * + * @return Progress + */ + public function progress(): Progress + { + return $this->lexer->progress(); + } } diff --git a/src/Progress.php b/src/Progress.php new file mode 100644 index 0000000..aff1889 --- /dev/null +++ b/src/Progress.php @@ -0,0 +1,99 @@ +current++; + + return $this; + } + + /** + * Retrieve the current progress + * + * @return int + */ + public function current(): int + { + return $this->current; + } + + /** + * Set the total possible progress + * + * @param int|null $total + * @return static + */ + public function setTotal(?int $total): static + { + $this->total ??= $total; + + return $this; + } + + /** + * Retrieve the total possible progress + * + * @return int|null + */ + public function total(): ?int + { + return $this->total; + } + + /** + * Retrieve the formatted percentage of the progress + * + * @return string|null + */ + public function format(): ?string + { + return is_null($percentage = $this->percentage()) ? null : number_format($percentage, 1) . '%'; + } + + /** + * Retrieve the percentage of the progress + * + * @return float|null + */ + public function percentage(): ?float + { + return is_null($fraction = $this->fraction()) ? null : $fraction * 100; + } + + /** + * Retrieve the fraction of the progress + * + * @return float|null + */ + public function fraction(): ?float + { + return $this->total ? $this->current / $this->total : null; + } +}