Skip to content

Commit

Permalink
Feat: Coroutine added context extend
Browse files Browse the repository at this point in the history
  • Loading branch information
cclilshy committed Feb 6, 2025
1 parent 8d756a1 commit beed872
Show file tree
Hide file tree
Showing 5 changed files with 150 additions and 12 deletions.
111 changes: 111 additions & 0 deletions src/Coroutine/Context.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
<?php declare(strict_types=1);
/**
* Copyright © 2024 cclilshy
* Email: [email protected]
*
* This software is licensed under the MIT License.
* For full license details, please visit: https://opensource.org/licenses/MIT
*
* By using this software, you agree to the terms of the license.
* Contributions, suggestions, and feedback are always welcome!
*/

namespace Ripple\Coroutine;

use Revolt\EventLoop\Suspension;
use Ripple\Types\Undefined;

use function Co\getSuspension;
use function spl_object_hash;
use function array_merge;
use function is_array;

/**
*
*/
class Context
{
/**
* @var array
*/
protected static array $context = [];

/**
* @param array|string $key
* @param mixed $value
*
* @return void
*/
public static function define(array|string $key, mixed $value = null): void
{
$hash = Context::getHash();
if (is_array($key)) {
Context::$context[$hash] = array_merge(Context::$context[$hash] ?? [], $key);
}

Context::$context[$hash][$key] = $value;
}

/**
* @param string|null $key
*
* @return mixed
*/
public static function get(string|null $key = null): mixed
{
$hash = Context::getHash();
if (!$key) {
return Context::$context[$hash] ?? new Undefined();
}
return Context::$context[$hash][$key] ?? new Undefined();
}

/**
* @param string $key
*
* @return void
*/
public static function remove(string $key): void
{
$hash = Context::getHash();
unset(Context::$context[$hash][$key]);
}

/**
* @param \Revolt\EventLoop\Suspension $targetSuspension
*
* @return void
*/
public static function extend(Suspension $targetSuspension): void
{
$currentSuspension = getSuspension();
if ($currentSuspension === $targetSuspension) {
return;
}

$currentHash = Context::getHash($currentSuspension);
$targetHash = Context::getHash($targetSuspension);
Context::$context[$currentHash] = (Context::$context[$targetHash] ?? []);
}

/**
* @return void
*/
public static function clear(): void
{
unset(Context::$context[Context::getHash()]);
}

/**
* @param \Revolt\EventLoop\Suspension|null $suspension
*
* @return string
*/
public static function getHash(Suspension|null $suspension = null): string
{
if (!$suspension) {
$suspension = getSuspension();
}
return spl_object_hash($suspension);
}
}
10 changes: 8 additions & 2 deletions src/Coroutine/Coroutine.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ class Coroutine extends Support
/*** @var WeakMap<object,WeakReference<Suspension>> */
private WeakMap $fiber2suspension;

/**
*
*/
public function __construct()
{
$this->registerOnFork();
Expand All @@ -72,7 +75,6 @@ public function getSuspension(): EventLoop\Suspension
if (!$fiber = Fiber::getCurrent()) {
return EventLoop::getSuspension();
}

return ($this->fiber2suspension[$fiber] ?? null)?->get() ?? EventLoop::getSuspension();
}

Expand Down Expand Up @@ -149,14 +151,18 @@ public function await(Promise $promise): mixed
public function async(Closure $closure): Promise
{
return promise(function (Closure $resolve, Closure $reject, Promise $promise) use ($closure) {
$suspension = new Suspension(function () use ($closure, $resolve, $reject) {
$currentSuspension = getSuspension();
$suspension = new Suspension(function () use ($closure, $resolve, $reject, $currentSuspension) {
Context::extend($currentSuspension);
try {
$resolve($closure());
} catch (EscapeException $exception) {
throw $exception;
} catch (Throwable $exception) {
$reject($exception);
return;
} finally {
Context::clear();
}
}, $resolve, $reject, $promise);

Expand Down
20 changes: 11 additions & 9 deletions src/Kernel.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
use Fiber;
use Revolt\EventLoop;
use Revolt\EventLoop\UnsupportedFeatureException;
use Ripple\Coroutine\Coroutine;
use Ripple\Coroutine\Suspension;
use Ripple\Process\Process;
use Throwable;
Expand Down Expand Up @@ -91,7 +92,7 @@ public function __construct()
*/
public function await(Promise $promise): mixed
{
return Coroutine\Coroutine::getInstance()->await($promise);
return Coroutine::getInstance()->await($promise);
}

/**
Expand All @@ -115,7 +116,7 @@ public static function getInstance(): Kernel
*/
public function async(Closure $closure): Promise
{
return Coroutine\Coroutine::getInstance()->async($closure);
return Coroutine::getInstance()->async($closure);
}

/**
Expand Down Expand Up @@ -225,22 +226,23 @@ public function wait(Closure|null $result = null): void

if (!$this->mainRunning) {
try {
Coroutine\Coroutine::resume($this->mainSuspension, $result);
Coroutine::resume($this->mainSuspension, $result);
if (Fiber::getCurrent()) {
Fiber::suspend();
}
} catch (Throwable) {
exit(0);
}
} else {
if ($result instanceof Closure) {
$result();
}
return;
}

if ($result instanceof Closure) {
$result();
}

try {
$this->mainRunning = false;
$result = Coroutine\Coroutine::suspend($this->mainSuspension);
$result = Coroutine::suspend($this->mainSuspension);
$this->mainRunning = true;

if ($result instanceof Closure) {
Expand All @@ -262,7 +264,7 @@ public function wait(Closure|null $result = null): void
*/
public function stop(): void
{
EventLoop::getDriver()->stop();
wait(static fn () => EventLoop::getDriver()->stop());
}

/**
Expand Down
19 changes: 19 additions & 0 deletions src/Types/Undefined.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php declare(strict_types=1);
/**
* Copyright © 2024 cclilshy
* Email: [email protected]
*
* This software is licensed under the MIT License.
* For full license details, please visit: https://opensource.org/licenses/MIT
*
* By using this software, you agree to the terms of the license.
* Contributions, suggestions, and feedback are always welcome!
*/

namespace Ripple\Types;

use stdClass;

class Undefined extends stdClass
{
}
2 changes: 1 addition & 1 deletion src/functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,7 @@ function resume(EventLoop\Suspension $suspension, mixed $result = null): mixed
*
* @return void
*/
function throw_(EventLoop\Suspension $suspension, Throwable $exception): void
function __throw(EventLoop\Suspension $suspension, Throwable $exception): void
{
Coroutine::throw($suspension, $exception);
}

0 comments on commit beed872

Please sign in to comment.