diff --git a/.dev/.gitignore b/.dev/.gitignore
index 2fbf865..d2bb2d1 100644
--- a/.dev/.gitignore
+++ b/.dev/.gitignore
@@ -1,2 +1,3 @@
debug
-coverage
\ No newline at end of file
+coverage
+bench.html
\ No newline at end of file
diff --git a/.dev/docker/php/Dockerfile b/.dev/docker/php/Dockerfile
index be79ff6..62b1287 100644
--- a/.dev/docker/php/Dockerfile
+++ b/.dev/docker/php/Dockerfile
@@ -22,7 +22,7 @@ RUN install-php-extensions bcmath
FROM base AS dev
-RUN install-php-extensions xdebug pcntl posix
+RUN install-php-extensions xdebug pcntl posix opcache
# Install and Configure XDebug
COPY ./xdebug.ini /usr/local/etc/php/conf.d/60_xdebug.ini
\ No newline at end of file
diff --git a/composer.json b/composer.json
index 54f448d..fbe9b86 100644
--- a/composer.json
+++ b/composer.json
@@ -41,11 +41,8 @@
"require": {
"php": ">=8.3",
"ext-bcmath": "*",
- "castor/io": "^0.3.0",
- "castor/bytes": "^0.2.0",
- "castor/functions": "^0.2.0",
- "brick/date-time": "^0.6",
- "brick/math": "^0.10"
+ "castor/functions": "^1.0",
+ "brick/date-time": "^0.7"
},
"require-dev": {
"phpunit/phpunit": "^10.5",
@@ -74,9 +71,11 @@
"test:unit": "phpunit --colors --exclude-group=integration --exclude-group=e2e",
"test:e2e": "phpunit --colors --group=e2e",
"test:integration": "phpunit --colors --group=integration",
- "bench": "phpbench run tests/Benchmark --report=default",
+ "bench": "phpbench run --report=default --output=html tests/Benchmark",
"profile": "phpbench xdebug:profile tests/Benchmark --progress=none",
"psalm": "psalm --no-cache --threads=5",
- "psalm:gh": "psalm --no-cache --threads=5 --long-progress --output-format=github"
+ "psalm:gh": "psalm --no-cache --threads=5 --long-progress --output-format=github",
+ "psalm:fix": "psalm --update-baseline",
+ "psalm:allow": "psalm --set-baseline=psalm-baseline.xml"
}
}
diff --git a/composer.lock b/composer.lock
index bece8ab..92a392d 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,20 +4,20 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "d09848fbd39c7f6f7807f5121329aab8",
+ "content-hash": "b9bd81608627bc7bde1681442ce7d079",
"packages": [
{
"name": "brick/date-time",
- "version": "0.6.5",
+ "version": "0.7.0",
"source": {
"type": "git",
"url": "https://github.com/brick/date-time.git",
- "reference": "db3b2508d7bb7c61deb7e7450a90bcc0439eb7e4"
+ "reference": "7b39737f630a0e5d2a2dc0834b0da77a065efaed"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/brick/date-time/zipball/db3b2508d7bb7c61deb7e7450a90bcc0439eb7e4",
- "reference": "db3b2508d7bb7c61deb7e7450a90bcc0439eb7e4",
+ "url": "https://api.github.com/repos/brick/date-time/zipball/7b39737f630a0e5d2a2dc0834b0da77a065efaed",
+ "reference": "7b39737f630a0e5d2a2dc0834b0da77a065efaed",
"shasum": ""
},
"require": {
@@ -27,7 +27,7 @@
"guzzlehttp/guzzle": "^7.0",
"php-coveralls/php-coveralls": "^2.2",
"phpunit/phpunit": "^10.5",
- "vimeo/psalm": "5.17.0"
+ "vimeo/psalm": "5.25.0"
},
"suggest": {
"ext-timezonedb": "This PECL extension provides up-to-date timezone information"
@@ -44,14 +44,32 @@
],
"description": "Date and time library",
"keywords": [
+ "DayOfWeek",
+ "LocalDateRange",
+ "LocalDateTime",
+ "LocalTime",
+ "Month",
+ "MonthDay",
+ "Year",
+ "YearMonth",
+ "YearMonthRange",
+ "YearWeek",
+ "ZonedDateTime",
"brick",
"date",
"datetime",
- "time"
+ "duration",
+ "instant",
+ "interval",
+ "localdate",
+ "period",
+ "stopwatch",
+ "time",
+ "timezone"
],
"support": {
"issues": "https://github.com/brick/date-time/issues",
- "source": "https://github.com/brick/date-time/tree/0.6.5"
+ "source": "https://github.com/brick/date-time/tree/0.7.0"
},
"funding": [
{
@@ -59,180 +77,21 @@
"type": "github"
}
],
- "time": "2024-06-19T21:32:48+00:00"
- },
- {
- "name": "brick/math",
- "version": "0.10.2",
- "source": {
- "type": "git",
- "url": "https://github.com/brick/math.git",
- "reference": "459f2781e1a08d52ee56b0b1444086e038561e3f"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/brick/math/zipball/459f2781e1a08d52ee56b0b1444086e038561e3f",
- "reference": "459f2781e1a08d52ee56b0b1444086e038561e3f",
- "shasum": ""
- },
- "require": {
- "ext-json": "*",
- "php": "^7.4 || ^8.0"
- },
- "require-dev": {
- "php-coveralls/php-coveralls": "^2.2",
- "phpunit/phpunit": "^9.0",
- "vimeo/psalm": "4.25.0"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "Brick\\Math\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "description": "Arbitrary-precision arithmetic library",
- "keywords": [
- "Arbitrary-precision",
- "BigInteger",
- "BigRational",
- "arithmetic",
- "bigdecimal",
- "bignum",
- "brick",
- "math"
- ],
- "support": {
- "issues": "https://github.com/brick/math/issues",
- "source": "https://github.com/brick/math/tree/0.10.2"
- },
- "funding": [
- {
- "url": "https://github.com/BenMorel",
- "type": "github"
- }
- ],
- "time": "2022-08-10T22:54:19+00:00"
- },
- {
- "name": "castor/bytes",
- "version": "0.2.0",
- "source": {
- "type": "git",
- "url": "git@github.com:castor-labs/php-lib-bytes.git",
- "reference": "510a569a62a4a0ea65a47921d86777e33024e54a"
- },
- "dist": {
- "type": "zip",
- "url": "https://castor-labs.github.io/php-packages/archive/castor/bytes/castor-bytes-510a569a62a4a0ea65a47921d86777e33024e54a-zip-8cb644.zip",
- "reference": "510a569a62a4a0ea65a47921d86777e33024e54a",
- "shasum": "239e492cfd5d5c7dd37870b49301c1cb13d26c6d"
- },
- "require": {
- "castor/functions": "^0.2.0",
- "castor/io": "^0.3.0",
- "php": ">=8.3"
- },
- "require-dev": {
- "friendsofphp/php-cs-fixer": "^3.49",
- "phpunit/phpunit": "^10.5",
- "vimeo/psalm": "^5.22"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "Castor\\": "src"
- }
- },
- "autoload-dev": {
- "psr-4": {
- "Castor\\": "tests"
- }
- },
- "scripts": {
- "pr": [
- "@fmt",
- "@psalm",
- "@test"
- ],
- "ci": [
- "@fmt:check",
- "@psalm:gh",
- "@test"
- ],
- "fmt": [
- "php-cs-fixer fix --diff --ansi"
- ],
- "fmt:check": [
- "php-cs-fixer fix --dry-run --diff --ansi"
- ],
- "test": [
- "phpunit --colors"
- ],
- "test:unit": [
- "phpunit --colors --exclude-group=integration --exclude-group=e2e"
- ],
- "test:e2e": [
- "phpunit --colors --group=e2e"
- ],
- "test:integration": [
- "phpunit --colors --group=integration"
- ],
- "psalm": [
- "psalm --no-cache --threads=5 --use-baseline"
- ],
- "psalm:gh": [
- "psalm --no-cache --threads=5 --long-progress --output-format=github --use-baseline"
- ],
- "psalm:fix": [
- "psalm --update-baseline"
- ],
- "psalm:allow": [
- "psalm --set-baseline=psalm-baseline.xml"
- ]
- },
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Matias Navarro Carter",
- "email": "mnavarrocarter@gmail.com",
- "role": "Lead Maintainer"
- }
- ],
- "description": "A useful value object to work with bytes as a slice of unsigned 8-bit integers",
- "homepage": "https://castor-labs.github.io/php-lib-std/packages/bytes",
- "keywords": [
- "bytes",
- "castor",
- "php",
- "php82",
- "stdlib",
- "uint8"
- ],
- "support": {
- "source": "https://github.com/castor-labs/php-lib-bytes/tree/0.2.0",
- "issues": "https://github.com/castor-labs/php-lib-bytes/issues"
- },
- "time": "2024-07-05T20:12:43+00:00"
+ "time": "2024-06-23T14:32:17+00:00"
},
{
"name": "castor/functions",
- "version": "0.2.0",
+ "version": "1.0.0",
"source": {
"type": "git",
"url": "git@github.com:castor-labs/php-lib-functions.git",
- "reference": "ee64f957cacbae447f6ac0fd090a704b7a91e671"
+ "reference": "98f0e07500eaf452da603ec687cf2b8bc923601b"
},
"dist": {
"type": "zip",
- "url": "https://castor-labs.github.io/php-packages/archive/castor/functions/castor-functions-ee64f957cacbae447f6ac0fd090a704b7a91e671-zip-03f9f1.zip",
- "reference": "ee64f957cacbae447f6ac0fd090a704b7a91e671",
- "shasum": "2a3be2f791a15386f65764505dc03415ac9fc936"
+ "url": "https://castor-labs.github.io/php-packages/archive/castor/functions/castor-functions-98f0e07500eaf452da603ec687cf2b8bc923601b-zip-2443fb.zip",
+ "reference": "98f0e07500eaf452da603ec687cf2b8bc923601b",
+ "shasum": "7f4b2aca3d970b4cdf5d87cfa833f11d650afc59"
},
"require": {
"ext-mbstring": "*",
@@ -320,116 +179,10 @@
"stdlib"
],
"support": {
- "source": "https://github.com/castor-labs/php-lib-functions/tree/0.2.0",
+ "source": "https://github.com/castor-labs/php-lib-functions/tree/1.0.0",
"issues": "https://github.com/castor-labs/php-lib-functions/issues"
},
- "time": "2024-07-05T17:02:58+00:00"
- },
- {
- "name": "castor/io",
- "version": "0.3.0",
- "source": {
- "type": "git",
- "url": "git@github.com:castor-labs/php-lib-io.git",
- "reference": "e669d4107862ae257cbcf414dbe7603219274f74"
- },
- "dist": {
- "type": "zip",
- "url": "https://castor-labs.github.io/php-packages/archive/castor/io/castor-io-e669d4107862ae257cbcf414dbe7603219274f74-zip-f49fef.zip",
- "reference": "e669d4107862ae257cbcf414dbe7603219274f74",
- "shasum": "6b766037300732d4e0ccc4e43c9378908e7dd638"
- },
- "require": {
- "php": ">=8.3"
- },
- "require-dev": {
- "friendsofphp/php-cs-fixer": "^3.49",
- "phpunit/phpunit": "^10.5",
- "vimeo/psalm": "^5.22"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "Castor\\Io\\": "src"
- },
- "files": [
- "include/functions.php"
- ]
- },
- "autoload-dev": {
- "psr-4": {
- "Castor\\Io\\": "tests"
- }
- },
- "scripts": {
- "pr": [
- "@fmt",
- "@psalm",
- "@test"
- ],
- "ci": [
- "@fmt:check",
- "@psalm:gh",
- "@test"
- ],
- "fmt": [
- "php-cs-fixer fix --diff --ansi"
- ],
- "fmt:check": [
- "php-cs-fixer fix --dry-run --diff --ansi"
- ],
- "test": [
- "phpunit --colors"
- ],
- "test:unit": [
- "phpunit --colors --exclude-group=integration --exclude-group=e2e"
- ],
- "test:e2e": [
- "phpunit --colors --group=e2e"
- ],
- "test:integration": [
- "phpunit --colors --group=integration"
- ],
- "psalm": [
- "psalm --no-cache --threads=5 --use-baseline"
- ],
- "psalm:gh": [
- "psalm --no-cache --threads=5 --long-progress --output-format=github --use-baseline"
- ],
- "psalm:fix": [
- "psalm --update-baseline"
- ],
- "psalm:allow": [
- "psalm --set-baseline=psalm-baseline.xml"
- ]
- },
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Matias Navarro Carter",
- "email": "mnavarrocarter@gmail.com",
- "role": "Lead Maintainer"
- }
- ],
- "description": "Input and output abstractions for PHP applications",
- "homepage": "https://castor-labs.github.io/php-lib-std/packages/io",
- "keywords": [
- "castor",
- "input",
- "io",
- "output",
- "php",
- "php82",
- "stdlib",
- "streams"
- ],
- "support": {
- "source": "https://github.com/castor-labs/php-lib-io/tree/0.3.0",
- "issues": "https://github.com/castor-labs/php-lib-io/issues"
- },
- "time": "2024-07-05T19:09:24+00:00"
+ "time": "2024-12-31T15:30:07+00:00"
}
],
"packages-dev": [
@@ -593,6 +346,66 @@
],
"time": "2024-04-13T18:00:56+00:00"
},
+ {
+ "name": "brick/math",
+ "version": "0.12.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/brick/math.git",
+ "reference": "f510c0a40911935b77b86859eb5223d58d660df1"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/brick/math/zipball/f510c0a40911935b77b86859eb5223d58d660df1",
+ "reference": "f510c0a40911935b77b86859eb5223d58d660df1",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^8.1"
+ },
+ "require-dev": {
+ "php-coveralls/php-coveralls": "^2.2",
+ "phpunit/phpunit": "^10.1",
+ "vimeo/psalm": "5.16.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Brick\\Math\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "description": "Arbitrary-precision arithmetic library",
+ "keywords": [
+ "Arbitrary-precision",
+ "BigInteger",
+ "BigRational",
+ "arithmetic",
+ "bigdecimal",
+ "bignum",
+ "bignumber",
+ "brick",
+ "decimal",
+ "integer",
+ "math",
+ "mathematics",
+ "rational"
+ ],
+ "support": {
+ "issues": "https://github.com/brick/math/issues",
+ "source": "https://github.com/brick/math/tree/0.12.1"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/BenMorel",
+ "type": "github"
+ }
+ ],
+ "time": "2023-11-29T23:19:16+00:00"
+ },
{
"name": "clue/ndjson-react",
"version": "v1.3.0",
@@ -6140,13 +5953,13 @@
],
"aliases": [],
"minimum-stability": "stable",
- "stability-flags": {},
+ "stability-flags": [],
"prefer-stable": false,
"prefer-lowest": false,
"platform": {
"php": ">=8.3",
"ext-bcmath": "*"
},
- "platform-dev": {},
+ "platform-dev": [],
"plugin-api-version": "2.6.0"
}
diff --git a/include/functions.php b/include/functions.php
index b9b0ae9..d32e5cb 100644
--- a/include/functions.php
+++ b/include/functions.php
@@ -32,7 +32,7 @@ function parse(string $uuid, bool $lazy = true): Uuid
/**
* Creates a UUID from the raw bytes.
*/
-function fromBytes(Bytes|string $bytes): Uuid
+function fromBytes(ByteArray|string $bytes): Uuid
{
return Any::fromBytes($bytes);
}
@@ -59,7 +59,7 @@ function max(): Uuid
/** @var null|Uuid $uuid */
static $uuid = null;
if (null === $uuid) {
- $uuid = Any::fromBytes(Bytes::fromUint8(
+ $uuid = Any::fromBytes(ByteArray::create([
0xFF,
0xFF,
0xFF,
@@ -76,7 +76,7 @@ function max(): Uuid
0xFF,
0xFF,
0xFF,
- ));
+ ]));
}
return $uuid;
@@ -90,7 +90,7 @@ function nil(): Uuid
/** @var null|Uuid $uuid */
static $uuid = null;
if (null === $uuid) {
- $uuid = Any::fromBytes(Bytes::fromUint8(
+ $uuid = Any::fromBytes(ByteArray::create([
0x00,
0x00,
0x00,
@@ -107,7 +107,7 @@ function nil(): Uuid
0x00,
0x00,
0x00,
- ));
+ ]));
}
return $uuid;
@@ -115,9 +115,9 @@ function nil(): Uuid
namespace Castor\Uuid\Ns;
-use Castor\Bytes;
use Castor\Uuid;
use Castor\Uuid\Any;
+use Castor\Uuid\ByteArray;
/**
* Returns the UUID namespace for Domain Name System (DNS).
@@ -127,7 +127,7 @@ function dns(): Uuid
/** @var null|Uuid $uuid */
static $uuid = null;
if (null === $uuid) {
- $uuid = Any::fromBytes(Bytes::fromUint8(
+ $uuid = Any::fromBytes(ByteArray::create([
0x6B,
0xA7,
0xB8,
@@ -144,7 +144,7 @@ function dns(): Uuid
0xD4,
0x30,
0xC8,
- ));
+ ]));
}
return $uuid;
@@ -158,7 +158,7 @@ function oid(): Uuid
/** @var null|Uuid $uuid */
static $uuid = null;
if (null === $uuid) {
- $uuid = Any::fromBytes(Bytes::fromUint8(
+ $uuid = Any::fromBytes(ByteArray::create([
0x6B,
0xA7,
0xB8,
@@ -175,7 +175,7 @@ function oid(): Uuid
0xD4,
0x30,
0xC8,
- ));
+ ]));
}
return $uuid;
@@ -189,7 +189,7 @@ function url(): Uuid
/** @var null|Uuid $uuid */
static $uuid = null;
if (null === $uuid) {
- $uuid = Any::fromBytes(Bytes::fromUint8(
+ $uuid = Any::fromBytes(ByteArray::create([
0x6B,
0xA7,
0xB8,
@@ -206,7 +206,7 @@ function url(): Uuid
0xD4,
0x30,
0xC8,
- ));
+ ]));
}
return $uuid;
@@ -220,7 +220,7 @@ function x500(): Uuid
/** @var null|Uuid $uuid */
static $uuid = null;
if (null === $uuid) {
- $uuid = Any::fromBytes(Bytes::fromUint8(
+ $uuid = Any::fromBytes(ByteArray::create([
0x6B,
0xA7,
0xB8,
@@ -237,7 +237,7 @@ function x500(): Uuid
0xD4,
0x30,
0xC8,
- ));
+ ]));
}
return $uuid;
diff --git a/phpbench.json b/phpbench.json
index 4e6e1ea..d7df3e6 100644
--- a/phpbench.json
+++ b/phpbench.json
@@ -1,5 +1,29 @@
{
"$schema":"./vendor/phpbench/phpbench/phpbench.schema.json",
"runner.bootstrap": "vendor/autoload.php",
- "xdebug.command_handler_output_dir": ".dev/debug"
+ "runner.output_mode": "time",
+ "runner.retry_threshold": 5,
+ "runner.php_config": {
+ "opcache.enable": true,
+ "opcache.enable_cli": true,
+ "opcache.jit": 1235,
+ "apc.enable": true,
+ "apc.enable_cli": true
+ },
+ "xdebug.command_handler_output_dir": ".dev/debug",
+ "report.generators": {
+ "default": {
+ "extends": "expression",
+ "title": "Castor UUID Benchmarks",
+ "break": [ "benchmark" ],
+ "cols": [ "benchmark", "subject", "set", "mem_peak", "mode", "best", "mean", "worst", "stdev", "rstdev" ]
+ }
+ },
+ "report.outputs": {
+ "html": {
+ "renderer": "html",
+ "path": ".dev/bench.html",
+ "title": "Castor UUID Benchmarks"
+ }
+ }
}
\ No newline at end of file
diff --git a/psalm-baseline.xml b/psalm-baseline.xml
new file mode 100644
index 0000000..1004d33
--- /dev/null
+++ b/psalm-baseline.xml
@@ -0,0 +1,91 @@
+
+
+
+
+ bytes->toArray(), $this->toString()]]]>
+
+
+ , 1: string}]]>
+
+
+
+
+
+
+ toArray(), $offset, $length)]]>
+
+
+
+
+
+
+
+
+
+ bytes->toHex(), 16, 10)]]>
+
+
+
+
+
+
+
+ bytes->toHex(), 16, 10)]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ >= 4]]>
+
+
+
+ > 4) | (($bytes[0] & 0x0F) << 4)]]>
+ > 4) | (($bytes[1] & 0x0F) << 4)]]>
+ > 4) | (($bytes[2] & 0x0F) << 4)]]>
+ > 4) | (($bytes[3] & 0x0F) << 4)]]>
+ > 4) | (($bytes[4] & 0x0F) << 4)]]>
+
+ > 4)]]>
+ > 4)]]>
+ > 4)]]>
+ > 4)]]>
+ > 4)]]>
+ > 4)]]>
+
+
+
+
+
+
+
+
+
diff --git a/psalm.xml b/psalm.xml
index 735479d..a25bd83 100644
--- a/psalm.xml
+++ b/psalm.xml
@@ -6,6 +6,7 @@
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
findUnusedBaselineEntry="true"
findUnusedCode="false"
+ errorBaseline="psalm-baseline.xml"
>
diff --git a/src/Uuid.php b/src/Uuid.php
index 5e2196f..f1ca782 100644
--- a/src/Uuid.php
+++ b/src/Uuid.php
@@ -16,6 +16,8 @@
namespace Castor;
+use Castor\Uuid\ByteArray;
+
/**
* This is the base contract for a UUID.
*
@@ -31,7 +33,7 @@ interface Uuid
*
* Implementors MUST NOT return the original reference stored inside the UUID.
*/
- public function getBytes(): Bytes;
+ public function getBytes(): ByteArray;
/**
* Returns the standard segmented hexadecimal representation of the UUID.
diff --git a/src/Uuid/Any.php b/src/Uuid/Any.php
index d0b03dc..943ca38 100644
--- a/src/Uuid/Any.php
+++ b/src/Uuid/Any.php
@@ -16,8 +16,7 @@
namespace Castor\Uuid;
-use Castor\Bytes;
-use Castor\Encoding\Error;
+use Castor\Encoding\Failure;
use Castor\RegExp;
use Castor\Str;
use Castor\Uuid;
@@ -35,7 +34,7 @@
*/
class Any implements Uuid, \Stringable, \JsonSerializable
{
- protected const string PATTERN = '/^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}$/';
+ protected const string PATTERN = '/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/';
protected const int STR_VERSION_OFFSET = 14;
@@ -51,7 +50,7 @@ class Any implements Uuid, \Stringable, \JsonSerializable
protected const int VAB = 8;
protected function __construct(
- private Bytes $bytes,
+ private ByteArray $bytes,
private string $string = '',
) {}
@@ -61,20 +60,20 @@ public function __toString(): string
}
/**
- * @return array{0: string}
+ * @return array{0: array<0,255>, 1: string}
*/
public function __serialize(): array
{
- return [$this->toString()];
+ return [$this->bytes->toArray(), $this->toString()];
}
/**
- * @param array{0: string} $data
+ * @param array{0: array<0,255>, 1: string} $data
*/
public function __unserialize(array $data): void
{
- $this->bytes = new Bytes('');
- $this->string = $data[0];
+ $this->bytes = ByteArray::create($data[0]);
+ $this->string = $data[1];
}
public function toString(): string
@@ -86,10 +85,14 @@ public function toString(): string
return $this->string;
}
- public function getBytes(): Bytes
+ public function getBytes(): ByteArray
{
- if ($this->bytes->len() === 0) {
- $this->bytes = self::parse($this->string, false)->getBytes();
+ if ($this->bytes->count() === 0) {
+ try {
+ $this->bytes = ByteArray::fromHex(Str\replace($this->string, '-', ''));
+ } catch (Failure $e) {
+ throw new \LogicException('Impossible error', previous : $e);
+ }
}
return clone $this->bytes;
@@ -123,13 +126,13 @@ public function toUrn(): string
*
* @throws ParsingError if the bytes are invalid
*/
- public static function fromBytes(Bytes|string $bytes): Uuid
+ public static function fromBytes(ByteArray|string $bytes): Uuid
{
if (\is_string($bytes)) {
- $bytes = new Bytes($bytes);
+ $bytes = ByteArray::fromRaw($bytes);
}
- if (self::LEN !== $bytes->len()) {
+ if (self::LEN !== $bytes->count()) {
throw new ParsingError('UUID must have 16 bytes.');
}
@@ -156,15 +159,17 @@ public static function fromBytes(Bytes|string $bytes): Uuid
*/
public static function parse(string $uuid, bool $lazy = true): Uuid
{
+ $uuid = Str\toLower($uuid);
+
if ($lazy) {
return self::lazy($uuid);
}
- $uuid = Str\toLower(Str\replace($uuid, '-', ''));
+ $uuid = Str\replace($uuid, '-', '');
try {
- $bytes = Bytes::fromHex($uuid);
- } catch (Error $e) {
+ $bytes = ByteArray::fromHex($uuid);
+ } catch (Failure $e) {
throw new ParsingError('Invalid hexadecimal in UUID.', previous: $e);
}
@@ -186,13 +191,13 @@ protected static function lazy(string $uuid): Uuid
}
return match ($uuid[self::STR_VERSION_OFFSET]) {
- '1' => new Version1(new Bytes(''), $uuid),
- '3' => new Version3(new Bytes(''), $uuid),
- '4' => new Version4(new Bytes(''), $uuid),
- '5' => new Version5(new Bytes(''), $uuid),
- '6' => new Version6(new Bytes(''), $uuid),
- '7' => new Version7(new Bytes(''), $uuid),
- default => new Any(new Bytes(''), $uuid)
+ '1' => new Version1(new ByteArray(0), $uuid),
+ '3' => new Version3(new ByteArray(0), $uuid),
+ '4' => new Version4(new ByteArray(0), $uuid),
+ '5' => new Version5(new ByteArray(0), $uuid),
+ '6' => new Version6(new ByteArray(0), $uuid),
+ '7' => new Version7(new ByteArray(0), $uuid),
+ default => new Any(new ByteArray(0), $uuid)
};
}
}
diff --git a/src/Uuid/ByteArray.php b/src/Uuid/ByteArray.php
new file mode 100644
index 0000000..23340e1
--- /dev/null
+++ b/src/Uuid/ByteArray.php
@@ -0,0 +1,85 @@
+>
+ */
+final class ByteArray extends \SplFixedArray
+{
+ /**
+ * @throws Failure
+ */
+ public static function fromHex(string $hex): self
+ {
+ return self::fromRaw(Hex\decode($hex));
+ }
+
+ public static function fromRaw(string $raw): self
+ {
+ $bytes = Bytes\unpack($raw);
+
+ return self::create($bytes);
+ }
+
+ /**
+ * @param array> $array
+ */
+ public static function create(array $array): self
+ {
+ $self = new self(\count($array));
+ $self->allocate(...$array);
+
+ return $self;
+ }
+
+ /**
+ * @param int<0,255> ...$bytes
+ */
+ public function allocate(int ...$bytes): void
+ {
+ // @var array $bytes
+ foreach ($bytes as $i => $byte) {
+ $this[$i] = $byte;
+ }
+ }
+
+ public function toRaw(): string
+ {
+ return Bytes\pack(...$this->toArray());
+ }
+
+ public function slice(int $offset, ?int $length = null): ByteArray
+ {
+ return self::create(Arr\slice($this->toArray(), $offset, $length));
+ }
+
+ public function toHex(): string
+ {
+ return Hex\encode($this->toRaw());
+ }
+
+ public function equals(ByteArray $bytes): bool
+ {
+ return $this == $bytes;
+ }
+}
diff --git a/src/Uuid/System/MacProvider.php b/src/Uuid/System/MacProvider.php
index 53ec596..94aaa09 100644
--- a/src/Uuid/System/MacProvider.php
+++ b/src/Uuid/System/MacProvider.php
@@ -16,7 +16,7 @@
namespace Castor\Uuid\System;
-use Castor\Bytes;
+use Castor\Uuid\ByteArray;
interface MacProvider
{
@@ -28,7 +28,7 @@ interface MacProvider
* In case is possible for the implementation not to be able to find any MAC, you must compose a
* MacProvider\RandUniMultiCast as a fallback.
*
- * @return Bytes[]
+ * @return ByteArray[]
*/
public function getMacAddresses(): array;
}
diff --git a/src/Uuid/System/MacProvider/Fallback.php b/src/Uuid/System/MacProvider/Fallback.php
index befa98d..50520ad 100644
--- a/src/Uuid/System/MacProvider/Fallback.php
+++ b/src/Uuid/System/MacProvider/Fallback.php
@@ -17,6 +17,7 @@
namespace Castor\Uuid\System\MacProvider;
use Castor\Bytes;
+use Castor\Uuid\ByteArray;
use Castor\Uuid\System\MacProvider;
use Random\Randomizer;
@@ -34,11 +35,11 @@ public function __construct(
) {}
/**
- * @return Bytes[]
+ * @return ByteArray[]
*/
public function getMacAddresses(): array
{
- $b = new Bytes($this->random->getBytes(6));
+ $b = ByteArray::fromRaw($this->random->getBytes(6));
$b[0] = $b[0] & 0xFE | 0x01;
return [$b];
diff --git a/src/Uuid/System/MacProvider/FromOs.php b/src/Uuid/System/MacProvider/FromOs.php
index 7427ae8..a36a81e 100644
--- a/src/Uuid/System/MacProvider/FromOs.php
+++ b/src/Uuid/System/MacProvider/FromOs.php
@@ -17,8 +17,8 @@
namespace Castor\Uuid\System\MacProvider;
use Castor\Arr;
-use Castor\Bytes;
-use Castor\Encoding\Error;
+use Castor\Encoding\Failure;
+use Castor\Uuid\ByteArray;
use Castor\Uuid\System\MacProvider;
final class FromOs implements MacProvider
@@ -26,15 +26,15 @@ final class FromOs implements MacProvider
/**
* Pattern to match nodes in ifconfig and ipconfig output.
*/
- private const IFCONFIG_PATTERN = '/[^:]([0-9a-f]{2}([:-])[0-9a-f]{2}(\2[0-9a-f]{2}){4})[^:]/i';
+ private const string IFCONFIG_PATTERN = '/[^:]([0-9a-f]{2}([:-])[0-9a-f]{2}(\2[0-9a-f]{2}){4})[^:]/i';
/**
* Pattern to match nodes in sysfs stream output.
*/
- private const SYSFS_PATTERN = '/^([0-9a-f]{2}:){5}[0-9a-f]{2}$/i';
+ private const string SYSFS_PATTERN = '/^([0-9a-f]{2}:){5}[0-9a-f]{2}$/i';
/**
- * @param null|Bytes[] $cached
+ * @param null|ByteArray[] $cached
*/
public function __construct(
private readonly MacProvider $next,
@@ -42,7 +42,7 @@ public function __construct(
) {}
/**
- * @return Bytes[]
+ * @return ByteArray[]
*/
public function getMacAddresses(): array
{
@@ -55,7 +55,7 @@ public function getMacAddresses(): array
}
/**
- * @return Bytes[]
+ * @return ByteArray[]
*
* TODO: Adjust to work within docker containers
*/
@@ -84,7 +84,7 @@ private function tryGetMacAddresses(): array
/**
* Returns MAC address from the first system interface via the sysfs interface.
*
- * @return Bytes[]
+ * @return ByteArray[]
*/
private function getFromSysFile(): array
{
@@ -112,7 +112,7 @@ private function getFromSysFile(): array
}
// Map any macs we have
- return [...Arr\map($macs, fn (string $mac): Bytes => Bytes::fromHex($this->cleanMac($mac)))];
+ return [...Arr\map($macs, fn (string $mac): ByteArray => ByteArray::fromHex($this->cleanMac($mac)))];
}
/**
@@ -124,11 +124,11 @@ private function getFromSysFile(): array
*
* @codeCoverageIgnore
*
- * @return Bytes[]
+ * @return ByteArray[]
*/
private function getFromConsoleCommand(): array
{
- /** @var Bytes[] $macs */
+ /** @var ByteArray[] $macs */
$macs = [];
$disabledFunctions = \strtolower((string) \ini_get('disable_functions'));
@@ -173,8 +173,8 @@ private function getFromConsoleCommand(): array
foreach ($matches[1] as $iface) {
if ('00:00:00:00:00:00' !== $iface && '00-00-00-00-00-00' !== $iface) {
try {
- $macs[] = Bytes::fromHex($this->cleanMac($iface));
- } catch (Error) {
+ $macs[] = ByteArray::fromHex($this->cleanMac($iface));
+ } catch (Failure) {
continue; // Ignore invalid macs
}
}
diff --git a/src/Uuid/System/State.php b/src/Uuid/System/State.php
index c214a7e..b069f3e 100644
--- a/src/Uuid/System/State.php
+++ b/src/Uuid/System/State.php
@@ -17,6 +17,7 @@
namespace Castor\Uuid\System;
use Castor\Bytes;
+use Castor\Uuid\ByteArray;
use Castor\Uuid\System\Time\Gregorian;
/**
@@ -27,7 +28,7 @@ interface State
/**
* Returns the system's clock sequence as bytes.
*/
- public function getClockSequence(): Bytes;
+ public function getClockSequence(): ByteArray;
/**
* Returns the system time.
@@ -37,5 +38,5 @@ public function getTime(): Gregorian;
/**
* Returns the system's node.
*/
- public function getNode(): Bytes;
+ public function getNode(): ByteArray;
}
diff --git a/src/Uuid/System/State/Fixed.php b/src/Uuid/System/State/Fixed.php
index 415663a..3de73a8 100644
--- a/src/Uuid/System/State/Fixed.php
+++ b/src/Uuid/System/State/Fixed.php
@@ -16,7 +16,7 @@
namespace Castor\Uuid\System\State;
-use Castor\Bytes;
+use Castor\Uuid\ByteArray;
use Castor\Uuid\System\State;
use Castor\Uuid\System\Time\Gregorian;
@@ -24,11 +24,11 @@
{
public function __construct(
private Gregorian $time,
- private Bytes $clockSeq,
- private Bytes $node,
+ private ByteArray $clockSeq,
+ private ByteArray $node,
) {}
- public function getClockSequence(): Bytes
+ public function getClockSequence(): ByteArray
{
return $this->clockSeq;
}
@@ -38,7 +38,7 @@ public function getTime(): Gregorian
return $this->time;
}
- public function getNode(): Bytes
+ public function getNode(): ByteArray
{
return $this->node;
}
diff --git a/src/Uuid/System/State/Standard.php b/src/Uuid/System/State/Standard.php
index dd0bf24..9b9db17 100644
--- a/src/Uuid/System/State/Standard.php
+++ b/src/Uuid/System/State/Standard.php
@@ -17,7 +17,7 @@
namespace Castor\Uuid\System\State;
use Brick\DateTime\Clock;
-use Castor\Bytes;
+use Castor\Uuid\ByteArray;
use Castor\Uuid\System\MacProvider;
use Castor\Uuid\System\MacProvider\Fallback;
use Castor\Uuid\System\MacProvider\FromOs;
@@ -30,18 +30,18 @@ final class Standard implements State
{
private static ?Standard $global = null;
- private Bytes $lastTimestamp;
- private Bytes $clockSequence;
- private Bytes $macAddress;
+ private ByteArray $lastTimestamp;
+ private ByteArray $clockSequence;
+ private ByteArray $macAddress;
public function __construct(
private readonly Clock $clock,
private readonly Randomizer $random,
private readonly MacProvider $macProvider,
) {
- $this->macAddress = new Bytes('');
- $this->clockSequence = new Bytes('');
- $this->lastTimestamp = new Bytes('');
+ $this->macAddress = new ByteArray(0);
+ $this->clockSequence = new ByteArray(0);
+ $this->lastTimestamp = new ByteArray(0);
}
public static function global(): Standard
@@ -58,9 +58,9 @@ public static function global(): Standard
return self::$global;
}
- public function getClockSequence(): Bytes
+ public function getClockSequence(): ByteArray
{
- if (0 === $this->clockSequence->len()) {
+ if (0 === $this->clockSequence->count()) {
$this->clockSequence = $this->generateClockSequence();
}
@@ -80,9 +80,9 @@ public function getTime(): Gregorian
return $gregorianTime;
}
- public function getNode(): Bytes
+ public function getNode(): ByteArray
{
- if (0 === $this->macAddress->len()) {
+ if (0 === $this->macAddress->count()) {
$macs = $this->macProvider->getMacAddresses();
$this->macAddress = $macs[0];
}
@@ -90,8 +90,8 @@ public function getNode(): Bytes
return $this->macAddress;
}
- private function generateClockSequence(): Bytes
+ private function generateClockSequence(): ByteArray
{
- return new Bytes(\pack('n*', $this->random->getBytes(2)));
+ return ByteArray::fromRaw($this->random->getBytes(2));
}
}
diff --git a/src/Uuid/System/Time.php b/src/Uuid/System/Time.php
index 2a16cb5..588fbd9 100644
--- a/src/Uuid/System/Time.php
+++ b/src/Uuid/System/Time.php
@@ -17,7 +17,6 @@
namespace Castor\Uuid\System;
use Brick\DateTime\Instant;
-use Brick\Math\BigInteger;
interface Time
{
@@ -27,7 +26,9 @@ interface Time
public function getInstant(): Instant;
/**
- * Returns the timestamp as an integer from this time.
+ * Returns the timestamp as a numeric integer from this time.
+ *
+ * @return numeric-string
*/
- public function getTimestamp(): BigInteger;
+ public function getTimestamp(): string;
}
diff --git a/src/Uuid/System/Time/Gregorian.php b/src/Uuid/System/Time/Gregorian.php
index b15fc06..6afd252 100644
--- a/src/Uuid/System/Time/Gregorian.php
+++ b/src/Uuid/System/Time/Gregorian.php
@@ -18,10 +18,8 @@
use Brick\DateTime\Clock;
use Brick\DateTime\Instant;
-use Brick\Math\BigInteger;
-use Brick\Math\RoundingMode;
-use Castor\Bytes;
-use Castor\Encoding\Error;
+use Castor\Encoding\Failure;
+use Castor\Uuid\ByteArray;
use Castor\Uuid\System\Time;
/**
@@ -41,34 +39,38 @@
private const string SECOND_INTERVALS = '10000000';
public function __construct(
- public Bytes $bytes,
+ public ByteArray $bytes,
) {
- if ($this->bytes->len() !== 8) {
+ if ($this->bytes->count() !== 8) {
throw new \InvalidArgumentException('Gregorian time must be 64 bits long');
}
}
- public static function fromTimestamp(BigInteger $timestamp): self
+ public static function fromTimestamp(string $timestamp): self
{
- $hex = \str_pad($timestamp->toBase(16), 16, '0', STR_PAD_LEFT);
+ if (!\is_numeric($timestamp)) {
+ throw new \InvalidArgumentException('Timestamp must be a valid numeric string');
+ }
+
+ $hex = \str_pad(\base_convert($timestamp, 10, 16), 16, '0', STR_PAD_LEFT);
try {
- return new self(Bytes::fromHex($hex));
- } catch (Error $e) {
+ return new self(ByteArray::fromHex($hex));
+ } catch (Failure $e) {
throw new \RuntimeException('Impossible error', previous: $e);
}
}
public static function fromInstant(Instant $instant): self
{
- $epochSeconds = BigInteger::of($instant->getEpochSecond());
- $nanoSeconds = BigInteger::of($instant->getNano());
+ $epochSeconds = (string) $instant->getEpochSecond();
+ $nanoSeconds = (string) $instant->getNano();
- $secondsTicks = $epochSeconds->multipliedBy(self::SECOND_INTERVALS);
- $nanoTicks = $nanoSeconds->dividedBy(100, RoundingMode::DOWN);
- $ticksSinceEpoch = $secondsTicks->plus($nanoTicks);
+ $secondsTicks = \bcmul($epochSeconds, self::SECOND_INTERVALS);
+ $nanoTicks = \bcdiv($nanoSeconds, '100');
+ $ticksSinceEpoch = \bcadd($secondsTicks, $nanoTicks);
- return self::fromTimestamp($ticksSinceEpoch->plus(self::GREGORIAN_TO_UNIX_OFFSET));
+ return self::fromTimestamp(\bcadd($ticksSinceEpoch, self::GREGORIAN_TO_UNIX_OFFSET, 0));
}
public static function now(Clock $clock): self
@@ -78,19 +80,19 @@ public static function now(Clock $clock): self
public function getInstant(): Instant
{
- $ticksSinceEpoch = $this->getTimestamp()->minus(self::GREGORIAN_TO_UNIX_OFFSET); // Subtract gregorian offset
+ $ticksSinceEpoch = \bcsub($this->getTimestamp(), self::GREGORIAN_TO_UNIX_OFFSET); // Subtract gregorian offset
- $epochSeconds = $ticksSinceEpoch->dividedBy(self::SECOND_INTERVALS, RoundingMode::DOWN);
- $nanoSeconds = $ticksSinceEpoch->remainder(self::SECOND_INTERVALS)->multipliedBy(100);
+ $epochSeconds = \bcdiv($ticksSinceEpoch, self::SECOND_INTERVALS);
+ $nanoSeconds = \bcmul(\bcmod($ticksSinceEpoch, self::SECOND_INTERVALS), '100');
- return Instant::of($epochSeconds->toInt(), $nanoSeconds->toInt());
+ return Instant::of((int) $epochSeconds, (int) $nanoSeconds);
}
/**
* Returns the number of 100 nanosecond intervals since 1582-10-15 00:00:00 UTC as a numeric string.
*/
- public function getTimestamp(): BigInteger
+ public function getTimestamp(): string
{
- return BigInteger::fromBase($this->bytes->toHex(), 16);
+ return \base_convert($this->bytes->toHex(), 16, 10);
}
}
diff --git a/src/Uuid/System/Time/Unix.php b/src/Uuid/System/Time/Unix.php
index 003a3ad..be40887 100644
--- a/src/Uuid/System/Time/Unix.php
+++ b/src/Uuid/System/Time/Unix.php
@@ -18,37 +18,39 @@
use Brick\DateTime\Clock;
use Brick\DateTime\Instant;
-use Brick\Math\BigInteger;
-use Brick\Math\RoundingMode;
-use Castor\Bytes;
-use Castor\Encoding\Error;
+use Castor\Encoding\Failure;
+use Castor\Uuid\ByteArray;
use Castor\Uuid\System\Time;
readonly class Unix implements Time
{
public function __construct(
- public Bytes $bytes
+ public ByteArray $bytes
) {
- if ($this->bytes->len() !== 6) {
+ if ($this->bytes->count() !== 6) {
throw new \InvalidArgumentException('Unix time must be 48 bits long');
}
}
public static function fromInstant(Instant $instant): self
{
- $secondsInMilliseconds = BigInteger::of($instant->getEpochSecond())->multipliedBy(1000);
- $nanosInMilliseconds = BigInteger::of($instant->getNano())->dividedBy(1e+6, RoundingMode::DOWN);
+ $secondsInMilliseconds = \bcmul((string) $instant->getEpochSecond(), '1000');
+ $nanosInMilliseconds = \bcdiv((string) $instant->getNano(), (string) 1e+6);
- return self::fromTimestamp($secondsInMilliseconds->plus($nanosInMilliseconds));
+ return self::fromTimestamp(\bcadd($secondsInMilliseconds, $nanosInMilliseconds, 0));
}
- public static function fromTimestamp(BigInteger $timestamp): self
+ public static function fromTimestamp(string $timestamp): self
{
- $hex = \str_pad($timestamp->toBase(16), 12, '0', STR_PAD_LEFT);
+ if (!\is_numeric($timestamp)) {
+ throw new \InvalidArgumentException('Timestamp must be a valid numeric string');
+ }
+
+ $hex = \str_pad(\base_convert($timestamp, 10, 16), 12, '0', STR_PAD_LEFT);
try {
- return new self(Bytes::fromHex($hex));
- } catch (Error $e) {
+ return new self(ByteArray::fromHex($hex));
+ } catch (Failure $e) {
throw new \RuntimeException('Impossible error', previous: $e);
}
}
@@ -61,16 +63,16 @@ public static function now(Clock $clock): self
public function getInstant(): Instant
{
$timestamp = $this->getTimestamp();
- $nanoSeconds = $timestamp->multipliedBy(1e+6);
+ $nanoSeconds = \bcmul($timestamp, (string) 1e+6);
- return Instant::of(0, $nanoSeconds->toInt());
+ return Instant::of(0, (int) $nanoSeconds);
}
/**
* Returns the number of millisecond elapsed since 1970-01-01 00:00:00 UTC.
*/
- public function getTimestamp(): BigInteger
+ public function getTimestamp(): string
{
- return BigInteger::fromBase($this->bytes->toHex(), 16);
+ return \base_convert($this->bytes->toHex(), 16, 10);
}
}
diff --git a/src/Uuid/Version1.php b/src/Uuid/Version1.php
index c54fe1c..8e8a675 100644
--- a/src/Uuid/Version1.php
+++ b/src/Uuid/Version1.php
@@ -48,7 +48,7 @@ public static function parse(string $uuid, bool $lazy = true): self
/**
* Creates a UUID Version 1 from the raw bytes.
*/
- public static function fromBytes(Bytes|string $bytes): self
+ public static function fromBytes(ByteArray|string $bytes): self
{
$uuid = parent::fromBytes($bytes);
if (!$uuid instanceof self) {
@@ -61,21 +61,22 @@ public static function fromBytes(Bytes|string $bytes): self
public static function generate(?State $state = null): self
{
$state = $state ?? Standard::global();
- $ts = $state->getTime()->bytes->asString();
- $node = $state->getNode()->asString();
- $seq = $state->getClockSequence()->asString();
-
- $bytes = new Bytes(
- $ts[4].
- $ts[5].
- $ts[6].
- $ts[7].
- $ts[2].
- $ts[3].
- $ts[0].
- $ts[1].
- $seq.
- $node
+ $ts = $state->getTime()->bytes;
+ $node = $state->getNode();
+ $seq = $state->getClockSequence();
+
+ $bytes = new ByteArray(self::LEN);
+ $bytes->allocate(
+ $ts[4],
+ $ts[5],
+ $ts[6],
+ $ts[7],
+ $ts[2],
+ $ts[3],
+ $ts[0],
+ $ts[1],
+ ...$seq,
+ ...$node
);
// We set the 7th octet to 0001 XXXX (version 1)
@@ -92,18 +93,18 @@ public static function generate(?State $state = null): self
*/
public function getTime(): Gregorian
{
- $bytes = $this->getBytes();
- $bytes[6] = $bytes[6] & 0x0F; // Unset the version bits
- $b = $bytes->asString();
- $bytes = new Bytes($b[6].$b[7].$b[4].$b[5].$b[0].$b[1].$b[2].$b[3]);
+ $b = $this->getBytes();
+ $b[6] &= 0x0F; // Unset the version bits
+ $b->setSize(8);
+ $b->allocate($b[6], $b[7], $b[4], $b[5], $b[0], $b[1], $b[2], $b[3]);
- return new Gregorian($bytes);
+ return new Gregorian($b);
}
/**
* Returns the node of this UUID.
*/
- public function getNode(): Bytes
+ public function getNode(): ByteArray
{
return $this->getBytes()->slice(10);
}
@@ -111,10 +112,10 @@ public function getNode(): Bytes
/**
* Returns the clock sequence of this UUID.
*/
- public function getClockSeq(): Bytes
+ public function getClockSeq(): ByteArray
{
$bytes = $this->getBytes();
- $bytes[8] = $bytes[8] & 0x3F; // Unset the variant bits
+ $bytes[8] &= 0x3F; // Unset the variant bits
return $bytes->slice(8, 2);
}
diff --git a/src/Uuid/Version3.php b/src/Uuid/Version3.php
index f6dbc34..3b472b6 100644
--- a/src/Uuid/Version3.php
+++ b/src/Uuid/Version3.php
@@ -48,7 +48,7 @@ public static function parse(string $uuid, bool $lazy = true): self
/**
* Creates a UUID Version 3 from the raw bytes.
*/
- public static function fromBytes(Bytes|string $bytes): self
+ public static function fromBytes(ByteArray|string $bytes): self
{
$uuid = parent::fromBytes($bytes);
if (!$uuid instanceof self) {
@@ -60,7 +60,7 @@ public static function fromBytes(Bytes|string $bytes): self
public static function create(Uuid $namespace, string $name): self
{
- $bytes = new Bytes(@\hash(self::HASHING_ALGO, $namespace->getBytes()->asString().$name, true));
+ $bytes = ByteArray::fromRaw(@\hash(self::HASHING_ALGO, $namespace->getBytes()->toRaw().$name, true));
// We set the 7th octet to 0011 XXXX (version 3)
$bytes[self::VEB] = $bytes[self::VEB] & 0x0F | 0x30; // AND 0000 1111 OR 0011 0000
diff --git a/src/Uuid/Version4.php b/src/Uuid/Version4.php
index 99abe54..8f3f72a 100644
--- a/src/Uuid/Version4.php
+++ b/src/Uuid/Version4.php
@@ -16,7 +16,6 @@
namespace Castor\Uuid;
-use Castor\Bytes;
use Castor\Uuid\System\Random;
use Random\Randomizer;
@@ -43,7 +42,7 @@ public static function parse(string $uuid, bool $lazy = true): self
return $v4;
}
- public static function fromBytes(Bytes|string $bytes): self
+ public static function fromBytes(ByteArray|string $bytes): self
{
$uuid = parent::fromBytes($bytes);
if (!$uuid instanceof self) {
@@ -57,7 +56,7 @@ public static function generate(?Randomizer $randomizer = null): self
{
$randomizer = $randomizer ?? Random::global();
- $bytes = new Bytes($randomizer->getBytes(self::LEN));
+ $bytes = ByteArray::fromRaw($randomizer->getBytes(self::LEN));
// We set the 7th octet to 0100 XXXX (version 4)
$bytes[self::VEB] = $bytes[self::VEB] & 0x0F | 0x40; // AND 0000 1111 OR 0100 0000
diff --git a/src/Uuid/Version5.php b/src/Uuid/Version5.php
index b72f695..befbfa3 100644
--- a/src/Uuid/Version5.php
+++ b/src/Uuid/Version5.php
@@ -43,7 +43,7 @@ public static function parse(string $uuid, bool $lazy = true): self
return $v5;
}
- public static function fromBytes(Bytes|string $bytes): self
+ public static function fromBytes(ByteArray|string $bytes): self
{
$uuid = parent::fromBytes($bytes);
if (!$uuid instanceof self) {
@@ -55,8 +55,8 @@ public static function fromBytes(Bytes|string $bytes): self
public static function create(Uuid $namespace, string $name): self
{
- $bytes = @\hash(self::HASHING_ALGO, $namespace->getBytes()->asString().$name, true);
- $bytes = new Bytes(\substr($bytes, 0, self::LEN));
+ $bytes = @\hash(self::HASHING_ALGO, $namespace->getBytes()->toRaw().$name, true);
+ $bytes = ByteArray::fromRaw(\substr($bytes, 0, self::LEN));
// We set the 7th octet to 0101 XXXX (version 5)
$bytes[self::VEB] = $bytes[self::VEB] & 0x0F | 0x50; // // AND 0000 1111 OR 0101 0000
diff --git a/src/Uuid/Version6.php b/src/Uuid/Version6.php
index ec42752..0cd459b 100644
--- a/src/Uuid/Version6.php
+++ b/src/Uuid/Version6.php
@@ -16,7 +16,6 @@
namespace Castor\Uuid;
-use Castor\Bytes;
use Castor\Uuid\System\State;
use Castor\Uuid\System\State\Standard;
use Castor\Uuid\System\Time\Gregorian;
@@ -48,7 +47,7 @@ public static function parse(string $uuid, bool $lazy = true): self
/**
* Creates a UUID Version 6 from the raw bytes.
*/
- public static function fromBytes(Bytes|string $bytes): self
+ public static function fromBytes(ByteArray|string $bytes): self
{
$uuid = parent::fromBytes($bytes);
if (!$uuid instanceof self) {
@@ -67,10 +66,12 @@ public static function generate(?State $state = null): self
{
$state = $state ?? Standard::global();
$time = $state->getTime()->bytes;
- $node = $state->getNode()->asString();
- $seq = $state->getClockSequence()->asString();
+ $seq = $state->getClockSequence();
+ $node = $state->getNode();
- $bytes = new Bytes($time->asString().$seq.$node);
+ // $bytes = new Bytes($time->asString().$seq.$node);
+ $bytes = new ByteArray(self::LEN);
+ $bytes->allocate(...$time, ...$seq, ...$node);
// We need to shift 4 bits to constraint this to a 60 bit number, discarding the first 4 bits
$bytes[0] = (($bytes[0] & 0x0F) << 4) | ($bytes[1] >> 4);
@@ -113,7 +114,7 @@ public function getTime(): Gregorian
/**
* Returns the node of this UUID.
*/
- public function getNode(): Bytes
+ public function getNode(): ByteArray
{
return $this->getBytes()->slice(10);
}
@@ -121,10 +122,10 @@ public function getNode(): Bytes
/**
* Returns the clock sequence of this UUID.
*/
- public function getClockSeq(): Bytes
+ public function getClockSeq(): ByteArray
{
$bytes = $this->getBytes();
- $bytes[8] = $bytes[8] & 0x3F; // Unset the variant bits
+ $bytes[8] &= 0x3F; // Unset the variant bits
return $bytes->slice(8, 2);
}
diff --git a/src/Uuid/Version7.php b/src/Uuid/Version7.php
index d2d2beb..c33e75b 100644
--- a/src/Uuid/Version7.php
+++ b/src/Uuid/Version7.php
@@ -52,7 +52,7 @@ public static function parse(string $uuid, bool $lazy = true): self
/**
* Creates a UUID Version 7 from the raw bytes.
*/
- public static function fromBytes(Bytes|string $bytes): self
+ public static function fromBytes(ByteArray|string $bytes): self
{
$uuid = parent::fromBytes($bytes);
if (!$uuid instanceof self) {
@@ -70,9 +70,10 @@ public static function generate(?Unix $timestamp = null, ?Randomizer $randomizer
$timestamp = $timestamp ?? Unix::fromInstant(Instant::now());
$randomizer = $randomizer ?? Random::global();
- $bytes = new Bytes(
- $timestamp->bytes->asString().
- $randomizer->getBytes(10),
+ $bytes = new ByteArray(16);
+ $bytes->allocate(
+ ...$timestamp->bytes,
+ ...Bytes\unpack($randomizer->getBytes(10)),
);
// We set the 7th octet to 0111 XXXX (version 7)
diff --git a/tests/Benchmark/CastorVsRamseyBench.php b/tests/Benchmark/CastorVsRamseyBench.php
new file mode 100644
index 0000000..718ce79
--- /dev/null
+++ b/tests/Benchmark/CastorVsRamseyBench.php
@@ -0,0 +1,234 @@
+toString();
+ }
+
+ #[Subject]
+ public function v1_generate_to_string_ramsey(): void
+ {
+ Ramsey::uuid1()->toString();
+ }
+
+ #[Subject]
+ public function v1_parse_to_bytes_castor(): void
+ {
+ Uuid\Version1::parse(self::V1_UUID)->getBytes()->toRaw();
+ }
+
+ #[Subject]
+ public function v1_parse_to_bytes_ramsey(): void
+ {
+ Ramsey::fromString(self::V1_UUID)->getBytes();
+ }
+
+ #[Subject]
+ public function v1_from_bytes_to_string_castor(): void
+ {
+ Uuid\Version1::fromBytes(self::V1_UUID_BIN)->toString();
+ }
+
+ #[Subject]
+ public function v1_from_bytes_to_string_ramsey(): void
+ {
+ Ramsey::fromBytes(self::V1_UUID_BIN)->toString();
+ }
+
+ #[Subject]
+ public function v4_generate_castor(): void
+ {
+ Uuid\Version4::generate();
+ }
+
+ #[Subject]
+ public function v4_generate_ramsey(): void
+ {
+ Ramsey::uuid4();
+ }
+
+ #[Subject]
+ public function v4_generate_to_string_castor(): void
+ {
+ Uuid\Version4::generate()->toString();
+ }
+
+ #[Subject]
+ public function v4_generate_to_string_ramsey(): void
+ {
+ Ramsey::uuid1()->toString();
+ }
+
+ #[Subject]
+ public function v4_parse_to_bytes_castor(): void
+ {
+ Uuid\Version4::parse(self::V4_UUID)->getBytes()->toRaw();
+ }
+
+ #[Subject]
+ public function v4_parse_to_bytes_ramsey(): void
+ {
+ Ramsey::fromString(self::V4_UUID)->getBytes();
+ }
+
+ #[Subject]
+ public function v4_from_bytes_to_string_castor(): void
+ {
+ Uuid\Version4::fromBytes(self::V4_UUID_BIN)->toString();
+ }
+
+ #[Subject]
+ public function v4_from_bytes_to_string_ramsey(): void
+ {
+ Ramsey::fromBytes(self::V4_UUID_BIN)->toString();
+ }
+
+ #[Subject]
+ public function v6_generate_castor(): void
+ {
+ Uuid\Version6::generate();
+ }
+
+ #[Subject]
+ public function v6_generate_ramsey(): void
+ {
+ Ramsey::uuid6();
+ }
+
+ #[Subject]
+ public function v6_generate_to_string_castor(): void
+ {
+ Uuid\Version4::generate()->toString();
+ }
+
+ #[Subject]
+ public function v6_generate_to_string_ramsey(): void
+ {
+ Ramsey::uuid1()->toString();
+ }
+
+ #[Subject]
+ public function v6_parse_to_bytes_castor(): void
+ {
+ Uuid\Version6::parse(self::V6_UUID)->getBytes()->toRaw();
+ }
+
+ #[Subject]
+ public function v6_parse_to_bytes_ramsey(): void
+ {
+ Ramsey::fromString(self::V6_UUID)->getBytes();
+ }
+
+ #[Subject]
+ public function v6_from_bytes_to_string_castor(): void
+ {
+ Uuid\Version6::fromBytes(self::V6_UUID_BIN)->toString();
+ }
+
+ #[Subject]
+ public function v6_from_bytes_to_string_ramsey(): void
+ {
+ Ramsey::fromBytes(self::V6_UUID_BIN)->toString();
+ }
+
+ #[Subject]
+ public function v7_generate_castor(): void
+ {
+ Uuid\Version7::generate();
+ }
+
+ #[Subject]
+ public function v7_generate_ramsey(): void
+ {
+ Ramsey::uuid7();
+ }
+
+ #[Subject]
+ public function v7_generate_to_string_castor(): void
+ {
+ Uuid\Version7::generate()->toString();
+ }
+
+ #[Subject]
+ public function v7_generate_to_string_ramsey(): void
+ {
+ Ramsey::uuid1()->toString();
+ }
+
+ #[Subject]
+ public function v7_parse_to_bytes_castor(): void
+ {
+ Uuid\Version7::parse(self::V7_UUID)->getBytes()->toRaw();
+ }
+
+ #[Subject]
+ public function v7_parse_to_bytes_ramsey(): void
+ {
+ Ramsey::fromString(self::V7_UUID)->getBytes();
+ }
+
+ #[Subject]
+ public function v7_from_bytes_to_string_castor(): void
+ {
+ Uuid\Version7::fromBytes(self::V7_UUID_BIN)->toString();
+ }
+
+ #[Subject]
+ public function v7_from_bytes_to_string_ramsey(): void
+ {
+ Ramsey::fromBytes(self::V7_UUID_BIN)->toString();
+ }
+}
diff --git a/tests/Benchmark/UuidGenerationBench.php b/tests/Benchmark/UuidGenerationBench.php
deleted file mode 100644
index 8a76880..0000000
--- a/tests/Benchmark/UuidGenerationBench.php
+++ /dev/null
@@ -1,72 +0,0 @@
- $unknown], JSON_THROW_ON_ERROR);
- $this->assertSame('O:15:"Castor\Uuid\Any":1:{i:0;s:36:"99cf973d-3fe7-8ee4-88bd-a0991a048794";}', $serialized);
+ $hash = \md5($serialized);
+
+ $this->assertSame(
+ 'e0d569ae9961295361a930432d035100',
+ $hash,
+ 'Does not match hash of serialized data: '.$serialized
+ );
$this->assertTrue($unknown->equals(\unserialize($serialized)));
$this->assertSame('{"uuid":"99cf973d-3fe7-8ee4-88bd-a0991a048794"}', $json);
$this->assertSame('99cf973d-3fe7-8ee4-88bd-a0991a048794', (string) $unknown);
diff --git a/tests/Uuid/ByteArrayTest.php b/tests/Uuid/ByteArrayTest.php
new file mode 100644
index 0000000..1634a80
--- /dev/null
+++ b/tests/Uuid/ByteArrayTest.php
@@ -0,0 +1,32 @@
+assertTrue($a->equals($b));
+ }
+}
diff --git a/tests/Uuid/System/Time/GregorianTest.php b/tests/Uuid/System/Time/GregorianTest.php
index 711b0d5..4b0c543 100644
--- a/tests/Uuid/System/Time/GregorianTest.php
+++ b/tests/Uuid/System/Time/GregorianTest.php
@@ -18,7 +18,6 @@
use Brick\DateTime\Clock\FixedClock;
use Brick\DateTime\Instant;
-use Brick\Math\BigInteger;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase;
@@ -34,7 +33,7 @@ public function it_creates_gregorian_time(): void
#[Test]
public function it_creates_from_timestamp(): void
{
- $instant = Gregorian::fromTimestamp(BigInteger::of('139127190010002012'))->getInstant();
+ $instant = Gregorian::fromTimestamp('139127190010002012')->getInstant();
$this->assertSame(1693426201, $instant->getEpochSecond());
$this->assertSame(201200, $instant->getNano()); // Nano precision is lost because of 100 nano intervals
}
diff --git a/tests/Uuid/Version1Test.php b/tests/Uuid/Version1Test.php
index da3ed69..63911d4 100644
--- a/tests/Uuid/Version1Test.php
+++ b/tests/Uuid/Version1Test.php
@@ -16,8 +16,6 @@
namespace Castor\Uuid;
-use Brick\Math\BigInteger;
-use Castor\Bytes;
use Castor\Uuid\System\Time\Gregorian;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\Attributes\TestWith;
@@ -29,9 +27,9 @@ class Version1Test extends TestCase
public function it_generates(): void
{
$state = new System\State\Fixed(
- Gregorian::fromTimestamp(BigInteger::of('139127190012012330')),
- Bytes::fromHex('0001'),
- Bytes::fromHex('00b0d063c226')
+ Gregorian::fromTimestamp('139127190012012330'),
+ ByteArray::fromHex('0001'),
+ ByteArray::fromHex('00b0d063c226')
);
$v1 = Version1::generate($state);
@@ -48,9 +46,9 @@ public function it_generates(): void
public function its_compatible_with_ramsey(): void
{
$state = new System\State\Fixed(
- new Gregorian(Bytes::fromHex('01ee4782395c14c4')),
- Bytes::fromHex('17ae'),
- Bytes::fromHex('0242ac1b0004')
+ new Gregorian(ByteArray::fromHex('01ee4782395c14c4')),
+ ByteArray::fromHex('17ae'),
+ ByteArray::fromHex('0242ac1b0004')
);
$v1 = Version1::generate($state);
@@ -86,12 +84,18 @@ public function it_parses_with_error(string $in, bool $lazy, string $expectedErr
#[Test]
public function it_serializes(): void
{
- $v1 = Version1::parse('5102999c-4771-11ee-be56-0242ac120002');
+ $v1 = Version1::parse('5102999c-4771-11ee-be56-0242ac120002', false);
$serialized = \serialize($v1);
$json = \json_encode(['uuid' => $v1], JSON_THROW_ON_ERROR);
- $this->assertSame('O:20:"Castor\Uuid\Version1":1:{i:0;s:36:"5102999c-4771-11ee-be56-0242ac120002";}', $serialized);
+ $hash = \md5($serialized);
+
+ $this->assertSame(
+ 'caba92f9403e49b428d6d7eec655bfbf',
+ $hash,
+ 'Does not match hash of serialized data: '.$serialized
+ );
$this->assertTrue($v1->equals(\unserialize($serialized)));
$this->assertSame('{"uuid":"5102999c-4771-11ee-be56-0242ac120002"}', $json);
$this->assertSame('5102999c-4771-11ee-be56-0242ac120002', (string) $v1);
diff --git a/tests/Uuid/Version3Test.php b/tests/Uuid/Version3Test.php
index 769a241..ec9dc41 100644
--- a/tests/Uuid/Version3Test.php
+++ b/tests/Uuid/Version3Test.php
@@ -47,12 +47,18 @@ public function it_parses_with_error(string $in, bool $lazy, string $expectedErr
#[Test]
public function it_serializes(): void
{
- $v3 = Version3::parse('a0f6aad0-cdf5-3ddc-a2ac-0bddb3249309');
+ $v3 = Version3::parse('a0f6aad0-cdf5-3ddc-a2ac-0bddb3249309', false);
$serialized = \serialize($v3);
$json = \json_encode(['uuid' => $v3], JSON_THROW_ON_ERROR);
- $this->assertSame('O:20:"Castor\Uuid\Version3":1:{i:0;s:36:"a0f6aad0-cdf5-3ddc-a2ac-0bddb3249309";}', $serialized);
+ $hash = \md5($serialized);
+
+ $this->assertSame(
+ 'e7c111909fae531b94cd9a64ab8c6355',
+ $hash,
+ 'Does not match hash of serialized data: '.$serialized
+ );
$this->assertTrue($v3->equals(\unserialize($serialized)));
$this->assertSame('{"uuid":"a0f6aad0-cdf5-3ddc-a2ac-0bddb3249309"}', $json);
$this->assertSame('a0f6aad0-cdf5-3ddc-a2ac-0bddb3249309', (string) $v3);
diff --git a/tests/Uuid/Version4Test.php b/tests/Uuid/Version4Test.php
index 7eebafc..8486b88 100644
--- a/tests/Uuid/Version4Test.php
+++ b/tests/Uuid/Version4Test.php
@@ -68,12 +68,18 @@ public function it_generates_unique_v4(): void
#[Test]
public function it_serializes(): void
{
- $v4 = Version4::parse('fa06067f-602d-404a-a34c-45c6a7744011');
+ $v4 = Version4::parse('fa06067f-602d-404a-a34c-45c6a7744011', false);
$serialized = \serialize($v4);
$json = \json_encode(['uuid' => $v4], JSON_THROW_ON_ERROR);
- $this->assertSame('O:20:"Castor\Uuid\Version4":1:{i:0;s:36:"fa06067f-602d-404a-a34c-45c6a7744011";}', $serialized);
+ $hash = \md5($serialized);
+
+ $this->assertSame(
+ '491e89b4ce01f6dbed1e5ea44cb565f2',
+ $hash,
+ 'Does not match hash of serialized data: '.$serialized
+ );
$this->assertTrue($v4->equals(\unserialize($serialized)));
$this->assertSame('{"uuid":"fa06067f-602d-404a-a34c-45c6a7744011"}', $json);
$this->assertSame('fa06067f-602d-404a-a34c-45c6a7744011', (string) $v4);
diff --git a/tests/Uuid/Version5Test.php b/tests/Uuid/Version5Test.php
index bdbd0cd..5f47e0d 100644
--- a/tests/Uuid/Version5Test.php
+++ b/tests/Uuid/Version5Test.php
@@ -50,12 +50,18 @@ public function it_parses_error(string $in, bool $lazy, string $expectedError):
#[Test]
public function it_serializes(): void
{
- $v5 = Version5::parse('5fe80e27-269a-5cce-98c3-989ddd181b71');
+ $v5 = Version5::parse('5fe80e27-269a-5cce-98c3-989ddd181b71', false);
$serialized = \serialize($v5);
$json = \json_encode(['uuid' => $v5], JSON_THROW_ON_ERROR);
- $this->assertSame('O:20:"Castor\Uuid\Version5":1:{i:0;s:36:"5fe80e27-269a-5cce-98c3-989ddd181b71";}', $serialized);
+ $hash = \md5($serialized);
+
+ $this->assertSame(
+ '47c422afb014e163834dc042a101dc2c',
+ $hash,
+ 'Does not match hash of serialized data: '.$serialized
+ );
$this->assertTrue($v5->equals(\unserialize($serialized)));
$this->assertSame('{"uuid":"5fe80e27-269a-5cce-98c3-989ddd181b71"}', $json);
$this->assertSame('5fe80e27-269a-5cce-98c3-989ddd181b71', (string) $v5);
diff --git a/tests/Uuid/Version6Test.php b/tests/Uuid/Version6Test.php
index 7ff80dc..d2bd353 100644
--- a/tests/Uuid/Version6Test.php
+++ b/tests/Uuid/Version6Test.php
@@ -16,8 +16,6 @@
namespace Castor\Uuid;
-use Brick\Math\BigInteger;
-use Castor\Bytes;
use Castor\Uuid\System\Time\Gregorian;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\Attributes\TestWith;
@@ -29,9 +27,9 @@ class Version6Test extends TestCase
public function it_generates(): void
{
$state = new System\State\Fixed(
- Gregorian::fromTimestamp(BigInteger::of('139127190012012330')),
- Bytes::fromHex('0001'),
- Bytes::fromHex('00b0d063c226')
+ Gregorian::fromTimestamp('139127190012012330'),
+ ByteArray::fromHex('0001'),
+ ByteArray::fromHex('00b0d063c226')
);
$v6 = Version6::generate($state);
@@ -72,12 +70,18 @@ public function it_parses_with_error(string $in, bool $lazy, string $expectedErr
#[Test]
public function it_serializes(): void
{
- $v6 = Version6::parse('1ee47713-343a-672a-8001-00b0d063c226');
+ $v6 = Version6::parse('1ee47713-343a-672a-8001-00b0d063c226', false);
$serialized = \serialize($v6);
$json = \json_encode(['uuid' => $v6], JSON_THROW_ON_ERROR);
- $this->assertSame('O:20:"Castor\Uuid\Version6":1:{i:0;s:36:"1ee47713-343a-672a-8001-00b0d063c226";}', $serialized);
+ $hash = \md5($serialized);
+
+ $this->assertSame(
+ '077ffc6a8dc1d17a78309ce9d3c8473c',
+ $hash,
+ 'Does not match hash of serialized data: '.$serialized
+ );
$this->assertTrue($v6->equals(\unserialize($serialized)));
$this->assertSame('{"uuid":"1ee47713-343a-672a-8001-00b0d063c226"}', $json);
$this->assertSame('1ee47713-343a-672a-8001-00b0d063c226', (string) $v6);
diff --git a/tests/Uuid/Version7Test.php b/tests/Uuid/Version7Test.php
index 7e7ac95..b24d9be 100644
--- a/tests/Uuid/Version7Test.php
+++ b/tests/Uuid/Version7Test.php
@@ -67,12 +67,18 @@ public function it_parses_with_error(string $in, bool $lazy, string $expectedErr
#[Test]
public function it_serializes(): void
{
- $v7 = Version7::parse('0190bddb-5bb6-7896-9c8b-18dbd0ab4337');
+ $v7 = Version7::parse('0190bddb-5bb6-7896-9c8b-18dbd0ab4337', false);
$serialized = \serialize($v7);
$json = \json_encode(['uuid' => $v7], JSON_THROW_ON_ERROR);
- $this->assertSame('O:20:"Castor\Uuid\Version7":1:{i:0;s:36:"0190bddb-5bb6-7896-9c8b-18dbd0ab4337";}', $serialized);
+ $hash = \md5($serialized);
+
+ $this->assertSame(
+ '7c63c60f49f177088cffdf53000b9b68',
+ $hash,
+ 'Does not match hash of serialized data: '.$serialized
+ );
$this->assertTrue($v7->equals(\unserialize($serialized)));
$this->assertSame('{"uuid":"0190bddb-5bb6-7896-9c8b-18dbd0ab4337"}', $json);
$this->assertSame('0190bddb-5bb6-7896-9c8b-18dbd0ab4337', (string) $v7);