[Uid] Add support for UUIDv6

This commit is contained in:
Nicolas Grekas 2020-03-15 00:49:12 +01:00
parent 7dc6da6c26
commit b705ee1b4b
5 changed files with 82 additions and 1 deletions

View File

@ -18,6 +18,7 @@ use Symfony\Component\Uid\UuidV1;
use Symfony\Component\Uid\UuidV3;
use Symfony\Component\Uid\UuidV4;
use Symfony\Component\Uid\UuidV5;
use Symfony\Component\Uid\UuidV6;
class UuidTest extends TestCase
{
@ -73,6 +74,18 @@ class UuidTest extends TestCase
$this->assertInstanceOf(UuidV5::class, $uuid);
}
public function testV6()
{
$uuid = Uuid::v6();
$this->assertInstanceOf(UuidV6::class, $uuid);
$uuid = new UuidV6(substr_replace(self::A_UUID_V1, '6', 14, 1));
$this->assertSame(85916308548.27832, $uuid->getTime());
$this->assertSame('3499710062d0', $uuid->getNode());
}
public function testBinary()
{
$uuid = new UuidV4(self::A_UUID_V4);

View File

@ -12,6 +12,8 @@
namespace Symfony\Component\Uid;
/**
* A ULID is lexicographically sortable and contains a 48-bit timestamp and 80-bit of crypto-random entropy.
*
* @see https://github.com/ulid/spec
*
* @experimental in 5.1

View File

@ -49,6 +49,7 @@ class Uuid implements \JsonSerializable
case UuidV3::TYPE: return new UuidV3($uuid);
case UuidV4::TYPE: return new UuidV4($uuid);
case UuidV5::TYPE: return new UuidV5($uuid);
case UuidV6::TYPE: return new UuidV6($uuid);
case NullUuid::TYPE: return new NullUuid();
case self::TYPE: return new self($uuid);
}
@ -76,6 +77,11 @@ class Uuid implements \JsonSerializable
return new UuidV5(uuid_generate_sha1($namespace->uuid, $name));
}
final public static function v6(): UuidV6
{
return new UuidV6();
}
public static function isValid(string $uuid): bool
{
if (__CLASS__ === static::class) {

View File

@ -12,7 +12,7 @@
namespace Symfony\Component\Uid;
/**
* A v1 UUID contains a 60-bit timestamp and ~60 extra unique bits.
* A v1 UUID contains a 60-bit timestamp and 63 extra unique bits.
*
* @experimental in 5.1
*

View File

@ -0,0 +1,60 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Uid;
/**
* A v6 UUID is lexicographically sortable and contains a 60-bit timestamp and 63 extra unique bits.
*
* @experimental in 5.1
*
* @author Nicolas Grekas <p@tchwork.com>
*/
class UuidV6 extends Uuid
{
protected const TYPE = 6;
// https://tools.ietf.org/html/rfc4122#section-4.1.4
// 0x01b21dd213814000 is the number of 100-ns intervals between the
// UUID epoch 1582-10-15 00:00:00 and the Unix epoch 1970-01-01 00:00:00.
private const TIME_OFFSET_INT = 0x01b21dd213814000;
private const TIME_OFFSET_COM = "\xfe\x4d\xe2\x2d\xec\x7e\xc0\x00";
public function __construct(string $uuid = null)
{
if (null === $uuid) {
$uuid = uuid_create(UUID_TYPE_TIME);
$this->uuid = substr($uuid, 15, 3).substr($uuid, 9, 4).$uuid[0].'-'.substr($uuid, 1, 4).'-6'.substr($uuid, 5, 3).substr($uuid, 18);
} else {
parent::__construct($uuid);
}
}
public function getTime(): float
{
$time = '0'.substr($this->uuid, 0, 8).substr($this->uuid, 9, 4).substr($this->uuid, 15, 3);
if (\PHP_INT_SIZE >= 8) {
return (hexdec($time) - self::TIME_OFFSET_INT) / 10000000;
}
$time = str_pad(hex2bin($time), 8, "\0", STR_PAD_LEFT);
$time = BinaryUtil::add($time, self::TIME_OFFSET_COM);
$time[0] = $time[0] & "\x7F";
return BinaryUtil::toBase($time, BinaryUtil::BASE10) / 10000000;
}
public function getNode(): string
{
return substr($this->uuid, 24);
}
}