Skip to content

Commit

Permalink
feat(type): add nonnull type (#392)
Browse files Browse the repository at this point in the history
  • Loading branch information
azjezz committed Jan 15, 2023
1 parent 506a2d6 commit fedb2e3
Show file tree
Hide file tree
Showing 5 changed files with 125 additions and 0 deletions.
1 change: 1 addition & 0 deletions docs/component/type.md
Expand Up @@ -32,6 +32,7 @@
- [non_empty_dict](./../../src/Psl/Type/non_empty_dict.php#L16)
- [non_empty_string](./../../src/Psl/Type/non_empty_string.php#L10)
- [non_empty_vec](./../../src/Psl/Type/non_empty_vec.php#L14)
- [nonnull](./../../src/Psl/Type/nonnull.php#L12)
- [null](./../../src/Psl/Type/null.php#L10)
- [nullable](./../../src/Psl/Type/nullable.php#L14)
- [num](./../../src/Psl/Type/num.php#L10)
Expand Down
2 changes: 2 additions & 0 deletions src/Psl/Internal/Loader.php
Expand Up @@ -315,6 +315,7 @@ final class Loader
'Psl\\Type\\mixed' => 'Psl/Type/mixed.php',
'Psl\\Type\\mixed_dict' => 'Psl/Type/mixed_dict.php',
'Psl\\Type\\mixed_vec' => 'Psl/Type/mixed_vec.php',
'Psl\\Type\\nonnull' => 'Psl/Type/nonnull.php',
'Psl\\Type\\null' => 'Psl/Type/null.php',
'Psl\\Type\\nullable' => 'Psl/Type/nullable.php',
'Psl\\Type\\optional' => 'Psl/Type/optional.php',
Expand Down Expand Up @@ -622,6 +623,7 @@ final class Loader
'Psl\\Type\\Internal\\IterableType' => 'Psl/Type/Internal/IterableType.php',
'Psl\\Type\\Internal\\MixedType' => 'Psl/Type/Internal/MixedType.php',
'Psl\\Type\\Internal\\NullType' => 'Psl/Type/Internal/NullType.php',
'Psl\\Type\\Internal\\NonNullType' => 'Psl/Type/Internal/NonNullType.php',
'Psl\\Type\\Internal\\NullableType' => 'Psl/Type/Internal/NullableType.php',
'Psl\\Type\\Internal\\OptionalType' => 'Psl/Type/Internal/OptionalType.php',
'Psl\\Type\\Internal\\PositiveIntType' => 'Psl/Type/Internal/PositiveIntType.php',
Expand Down
66 changes: 66 additions & 0 deletions src/Psl/Type/Internal/NonNullType.php
@@ -0,0 +1,66 @@
<?php

declare(strict_types=1);

namespace Psl\Type\Internal;

use Psl\Type;
use Psl\Type\Exception\AssertException;
use Psl\Type\Exception\CoercionException;

/**
* @ara-extends Type\Type<nonnull>
*
* @extends Type\Type<mixed>
*
* @internal
*/
final class NonNullType extends Type\Type
{
/**
* @psalm-assert-if-true mixed $value
*
* @ara-assert-if-true nonnull $value
*/
public function matches(mixed $value): bool
{
return null !== $value;
}

/**
* @ara-return nonnull
*
* @return mixed
*/
public function coerce(mixed $value): mixed
{
if (null !== $value) {
return $value;
}

throw CoercionException::withValue($value, $this->toString(), $this->getTrace());
}

/**
* @ara-assert nonnull $value
*
* @psalm-assert mixed $value
*
* @ara-return nonnull
*
* @return mixed
*/
public function assert(mixed $value): mixed
{
if (null !== $value) {
return $value;
}

throw AssertException::withValue($value, $this->toString(), $this->getTrace());
}

public function toString(): string
{
return 'nonnull';
}
}
15 changes: 15 additions & 0 deletions src/Psl/Type/nonnull.php
@@ -0,0 +1,15 @@
<?php

declare(strict_types=1);

namespace Psl\Type;

/**
* @ara-return TypeInterface<nonnull>
*
* @return TypeInterface<mixed>
*/
function nonnull(): TypeInterface
{
return new Internal\NonNullType();
}
41 changes: 41 additions & 0 deletions tests/unit/Type/NonNullTypeTest.php
@@ -0,0 +1,41 @@
<?php

declare(strict_types=1);

namespace Psl\Tests\Unit\Type;

use Psl\Type;

final class NonNullTypeTest extends TypeTest
{
public function getType(): Type\TypeInterface
{
return Type\nonnull();
}

public function getValidCoercions(): iterable
{
yield [$_ = Type\bool(), $_];
yield [$_ = 1, $_];
yield [$_ = 0, $_];
yield [$_ = false, $_];
yield [$_ = true, $_];
yield [$_ = '', $_];
yield [$_ = 'null', $_];
yield [$_ = 'foo', $_];
yield [$_ = [null], $_];
yield [$_ = [], $_];
yield [$_ = [1, 2, 3], $_];
yield [$_ = $this->stringable(''), $_];
}

public function getInvalidCoercions(): iterable
{
yield [null];
}

public function getToStringExamples(): iterable
{
yield [$this->getType(), 'nonnull'];
}
}

0 comments on commit fedb2e3

Please sign in to comment.