diff --git a/util/util/BitField.ts b/util/util/BitField.ts
new file mode 100644
index 00000000..728dc632
--- /dev/null
+++ b/util/util/BitField.ts
@@ -0,0 +1,143 @@
+"use strict";
+
+// https://github.com/discordjs/discord.js/blob/master/src/util/BitField.js
+// Apache License Version 2.0 Copyright 2015 - 2021 Amish Shah
+
+export type BitFieldResolvable = number | BigInt | BitField | string | BitFieldResolvable[];
+
+/**
+ * Data structure that makes it easy to interact with a bitfield.
+ */
+export class BitField {
+ public bitfield: bigint = BigInt(0);
+
+ public static FLAGS: Record<string, bigint> = {};
+
+ constructor(bits: BitFieldResolvable = 0) {
+ this.bitfield = BitField.resolve.call(this, bits);
+ }
+
+ /**
+ * Checks whether the bitfield has a bit, or any of multiple bits.
+ */
+ any(bit: BitFieldResolvable): boolean {
+ return (this.bitfield & BitField.resolve.call(this, bit)) !== 0n;
+ }
+
+ /**
+ * Checks if this bitfield equals another
+ */
+ equals(bit: BitFieldResolvable): boolean {
+ return this.bitfield === BitField.resolve.call(this, bit);
+ }
+
+ /**
+ * Checks whether the bitfield has a bit, or multiple bits.
+ */
+ has(bit: BitFieldResolvable): boolean {
+ if (Array.isArray(bit)) return bit.every((p) => this.has(p));
+ const BIT = BitField.resolve.call(this, bit);
+ return (this.bitfield & BIT) === BIT;
+ }
+
+ /**
+ * Gets all given bits that are missing from the bitfield.
+ */
+ missing(bits: BitFieldResolvable) {
+ if (!Array.isArray(bits)) bits = new BitField(bits).toArray();
+ return bits.filter((p) => !this.has(p));
+ }
+
+ /**
+ * Freezes these bits, making them immutable.
+ */
+ freeze(): Readonly<BitField> {
+ return Object.freeze(this);
+ }
+
+ /**
+ * Adds bits to these ones.
+ * @param {...BitFieldResolvable} [bits] Bits to add
+ * @returns {BitField} These bits or new BitField if the instance is frozen.
+ */
+ add(...bits: BitFieldResolvable[]): BitField {
+ let total = 0n;
+ for (const bit of bits) {
+ total |= BitField.resolve.call(this, bit);
+ }
+ if (Object.isFrozen(this)) return new BitField(this.bitfield | total);
+ this.bitfield |= total;
+ return this;
+ }
+
+ /**
+ * Removes bits from these.
+ * @param {...BitFieldResolvable} [bits] Bits to remove
+ */
+ remove(...bits: BitFieldResolvable[]) {
+ let total = 0n;
+ for (const bit of bits) {
+ total |= BitField.resolve.call(this, bit);
+ }
+ if (Object.isFrozen(this)) return new BitField(this.bitfield & ~total);
+ this.bitfield &= ~total;
+ return this;
+ }
+
+ /**
+ * Gets an object mapping field names to a {@link boolean} indicating whether the
+ * bit is available.
+ * @param {...*} hasParams Additional parameters for the has method, if any
+ */
+ serialize() {
+ const serialized: Record<string, boolean> = {};
+ for (const [flag, bit] of Object.entries(BitField.FLAGS)) serialized[flag] = this.has(bit);
+ return serialized;
+ }
+
+ /**
+ * Gets an {@link Array} of bitfield names based on the bits available.
+ */
+ toArray(): string[] {
+ return Object.keys(BitField.FLAGS).filter((bit) => this.has(bit));
+ }
+
+ toJSON() {
+ return this.bitfield;
+ }
+
+ valueOf() {
+ return this.bitfield;
+ }
+
+ *[Symbol.iterator]() {
+ yield* this.toArray();
+ }
+
+ /**
+ * Data that can be resolved to give a bitfield. This can be:
+ * * A bit number (this can be a number literal or a value taken from {@link BitField.FLAGS})
+ * * An instance of BitField
+ * * An Array of BitFieldResolvable
+ * @typedef {number|BitField|BitFieldResolvable[]} BitFieldResolvable
+ */
+
+ /**
+ * Resolves bitfields to their numeric form.
+ * @param {BitFieldResolvable} [bit=0] - bit(s) to resolve
+ * @returns {number}
+ */
+ static resolve(bit: BitFieldResolvable = 0n): bigint {
+ // @ts-ignore
+ const FLAGS = this.FLAGS || this.constructor?.FLAGS;
+ if ((typeof bit === "number" || typeof bit === "bigint") && bit >= 0n) return BigInt(bit);
+ if (bit instanceof BitField) return bit.bitfield;
+ if (Array.isArray(bit)) {
+ // @ts-ignore
+ const resolve = this.constructor?.resolve || this.resolve;
+ return bit.map((p) => resolve.call(this, p)).reduce((prev, p) => BigInt(prev) | BigInt(p), 0n);
+ }
+ if (typeof bit === "string" && typeof FLAGS[bit] !== "undefined") return FLAGS[bit];
+ throw new RangeError("BITFIELD_INVALID: " + bit);
+ }
+}
|