"use strict";
const crypto = require("crypto");
const utils = require("../utils");
/** @module types */
/**
* Represents an immutable universally unique identifier (UUID). A UUID represents a 128-bit value.
*/
class Uuid {
/**
* Used to check if the UUID is in a correct format
* Source: https://stackoverflow.com/a/6640851
* Verified also with documentation of UUID library in Rust: https://docs.rs/uuid/latest/uuid/
*/
static uuidRegex =
/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
/**
* @type {Buffer}
* @private
*/
#raw;
/**
* Creates a new instance of Uuid based on a Buffer
* @param {Buffer} buffer The 16-length buffer.
*/
constructor(buffer) {
if (!buffer || buffer.length !== 16) {
throw new TypeError(
"You must provide a buffer containing 16 bytes",
);
}
this.#raw = buffer;
}
/**
* Returns the underlying buffer
* @readonly
* @type Buffer
*/
get buffer() {
return this.#raw;
}
set buffer(_) {
throw new SyntaxError("UUID buffer is read-only");
}
/**
* Parses a string representation of a Uuid
* @param {string} value
* @returns {Uuid}
*/
static fromString(value) {
if (typeof value !== "string" || !Uuid.uuidRegex.test(value)) {
throw new Error(
"Invalid string representation of Uuid, it should be in the 00000000-0000-0000-0000-000000000000 format",
);
}
return new Uuid(
utils.allocBufferFromString(value.replace(/-/g, ""), "hex"),
);
}
/**
* Creates a new random (version 4) Uuid.
* @param {function} [callback] Optional callback to be invoked with the error as
* first parameter and the created Uuid as second parameter.
* @returns {Uuid}
*/
static random(callback) {
function getRandomBytes(cb) {
return crypto.randomBytes(16, cb);
}
if (callback) {
getRandomBytes(function (err, buffer) {
if (err) {
return callback(err);
}
return callback(null, createUuidFromBuffer(buffer));
});
} else {
const buffer = getRandomBytes();
return createUuidFromBuffer(buffer);
}
}
/**
* Gets the bytes representation of a Uuid
* @returns {Buffer}
*/
getBuffer() {
return this.buffer;
}
/**
* Compares this object to the specified object.
* The result is true if and only if the argument is not null, is a UUID object, and contains the same value, bit for bit, as this UUID.
* @param {Uuid} other The other value to test for equality.
*/
equals(other) {
if (!(other instanceof Uuid)) {
return false;
}
return this.buffer.compare(other.getBuffer()) == 0;
}
/**
* Returns a string representation of the value of this Uuid instance.
* 32 hex separated by hyphens, in the form of 00000000-0000-0000-0000-000000000000.
* @returns {string}
*/
toString() {
// 32 hex representation of the Buffer
const hexValue = this.buffer.toString("hex");
return `${hexValue.slice(0, 8)}-${hexValue.slice(8, 12)}-${hexValue.slice(12, 16)}-${hexValue.slice(16, 20)}-${hexValue.slice(20)}`;
}
/**
* Provide the name of the constructor and the string representation
* @returns {string}
*/
inspect() {
return `${this.constructor.name}: ${this.toString()}`;
}
/**
* Returns the string representation.
* Method used by the native JSON.stringify() to serialize this instance.
*/
toJSON() {
return this.toString();
}
/**
* @package
* @param {Buffer} buffer
* @returns {Uuid}
*/
static fromRust(buffer) {
return new Uuid(buffer);
}
/**
* @package
* @returns {rust.UuidWrapper}
*/
getInternal() {
return this.#raw;
}
}
/**
* Returns new Uuid
* @private
* @returns {Uuid}
*/
function createUuidFromBuffer(buffer) {
// clear the version
buffer[6] &= 0x0f;
// set the version 4
buffer[6] |= 0x40;
// clear the variant
buffer[8] &= 0x3f;
// set the IETF variant
buffer[8] |= 0x80;
return new Uuid(buffer);
}
module.exports = Uuid;