From f6dc1effa17f5efd647a08282063512af0b7f03c Mon Sep 17 00:00:00 2001 From: Igor Klepacki Date: Tue, 2 Sep 2025 02:59:00 +0200 Subject: [PATCH 1/2] fix: indentation of collapsible sections in readme --- README.md | 90 +++++++++++++++++++++++++++---------------------------- 1 file changed, 45 insertions(+), 45 deletions(-) diff --git a/README.md b/README.md index 48aa0e1..c3c9ebf 100644 --- a/README.md +++ b/README.md @@ -199,8 +199,8 @@ function validateMeatAddition(currentPizza: Bitflag, toppingsToAdd: Bitflag) { > [!TIP] > Adding the same flag multiple times is idempotent - it won't change the result. -
- Usage Examples +
+ Usage Examples ```ts bitflag(flags.MY_FLAG).add(flags.MY_OTHER_FLAG); // single defined @@ -208,7 +208,7 @@ function validateMeatAddition(currentPizza: Bitflag, toppingsToAdd: Bitflag) { bitflag(flags.MY_FLAG).add(flags.MY_OTHER_FLAG, makeBitflag(1 << 2)); // mixed ``` -
+
- `.remove(...Bitflag[])` Removes the specified flags from the current set. Returns a new number wrapped in `Bitflag` as the updated flags. @@ -216,8 +216,8 @@ function validateMeatAddition(currentPizza: Bitflag, toppingsToAdd: Bitflag) { > [!TIP] > Removing non-existent flags has no effect and won't change the result. -
- Usage Examples +
+ Usage Examples ```ts bitflag(flags.READ | flags.WRITE).remove(flags.WRITE); // single defined @@ -225,13 +225,13 @@ function validateMeatAddition(currentPizza: Bitflag, toppingsToAdd: Bitflag) { bitflag(flags.READ | flags.WRITE).remove(flags.WRITE, makeBitflag(1 << 3)); // mixed ``` -
+
- `.toggle(...Bitflag[])` Toggles the specified flags in the current set - adds them if not present, removes them if present. Returns a new number wrapped in `Bitflag` as the updated flags. -
- Usage Examples +
+ Usage Examples ```ts bitflag(flags.READ).toggle(flags.WRITE); // single defined @@ -239,7 +239,7 @@ function validateMeatAddition(currentPizza: Bitflag, toppingsToAdd: Bitflag) { bitflag(flags.READ).toggle(flags.WRITE, makeBitflag(1 << 4)); // mixed ``` -
+
- `.has(...Bitflag[])` Checks if all the specified flags are set in the current set. Returns `true` if all flags are present, `false` otherwise. @@ -247,8 +247,8 @@ function validateMeatAddition(currentPizza: Bitflag, toppingsToAdd: Bitflag) { > [!TIP] > Passing no arguments to `.has()` always returns `false`. -
- Usage Examples +
+ Usage Examples ```ts bitflag(flags.READ | flags.WRITE).has(flags.READ); // single defined @@ -259,7 +259,7 @@ function validateMeatAddition(currentPizza: Bitflag, toppingsToAdd: Bitflag) { bitflag(flags.READ | flags.WRITE).has(flags.READ, makeBitflag(1 << 1)); // mixed ``` -
+
- `.hasAny(...Bitflag[])` Checks if any of the specified flags are set in the current set. Returns `true` if at least one flag is present, `false` if none are present. @@ -267,8 +267,8 @@ function validateMeatAddition(currentPizza: Bitflag, toppingsToAdd: Bitflag) { > [!TIP] > Passing no arguments to `.hasAny()` always returns `false`. -
- Usage Examples +
+ Usage Examples ```ts bitflag(flags.READ | flags.WRITE).hasAny(flags.EXECUTE); // single defined @@ -276,7 +276,7 @@ function validateMeatAddition(currentPizza: Bitflag, toppingsToAdd: Bitflag) { bitflag(flags.READ).hasAny(flags.EXECUTE, makeBitflag(1 << 0)); // mixed ``` -
+
- `.hasExact(...Bitflag[])` Checks if the current set matches exactly the specified flags - no more, no less. Returns `true` if the flags match exactly, `false` otherwise. @@ -284,8 +284,8 @@ function validateMeatAddition(currentPizza: Bitflag, toppingsToAdd: Bitflag) { > [!TIP] > Calling `.hasExact()` with no arguments checks if the current value is exactly zero. -
- Usage Examples +
+ Usage Examples ```ts bitflag(flags.READ | flags.WRITE).hasExact(flags.READ, flags.WRITE); // single defined exact match @@ -293,19 +293,19 @@ function validateMeatAddition(currentPizza: Bitflag, toppingsToAdd: Bitflag) { bitflag(flags.READ).hasExact(makeBitflag(1 << 0)); // mixed ``` -
+
- `.clear()` Clears all flags, setting the value to zero. Returns a new number wrapped in `Bitflag` with value 0. -
- Usage Examples +
+ Usage Examples ```ts bitflag(flags.ALL).clear(); // returns 0 as Bitflag ``` -
+
- `.describe(flagDefinitions?: BitflagsDefinitions)` Returns an iterator that yields `FlagDescription` objects for each set bit, providing detailed information about the flags including name, value, and bit position visualization. @@ -330,8 +330,8 @@ function validateMeatAddition(currentPizza: Bitflag, toppingsToAdd: Bitflag) { Examples: -
- Basic Usage with Flag Definitions +
+ Basic Usage with Flag Definitions ```ts [...bitflag(flags.READ | flags.WRITE).describe(flags)]; @@ -369,10 +369,10 @@ function validateMeatAddition(currentPizza: Bitflag, toppingsToAdd: Bitflag) { ]; ``` -
+
-
- Generic Bit Names (No Definitions) +
+ Generic Bit Names (No Definitions) ```ts // Without definitions - shows generic BIT_X names @@ -407,10 +407,10 @@ function validateMeatAddition(currentPizza: Bitflag, toppingsToAdd: Bitflag) { ]; ``` -
+
-
- Mixed Known and Unknown Flags +
+ Mixed Known and Unknown Flags ```ts // Mixed known and unknown flags @@ -449,10 +449,10 @@ function validateMeatAddition(currentPizza: Bitflag, toppingsToAdd: Bitflag) { ]; ``` -
+
-
- Zero Value Special Case +
+ Zero Value Special Case ```ts // Zero value special case @@ -478,10 +478,10 @@ function validateMeatAddition(currentPizza: Bitflag, toppingsToAdd: Bitflag) { ]; ``` -
+
-
- High Bit Positions (15 & 30) +
+ High Bit Positions (15 & 30) ```ts // High bit positions (bit 15 and 30) @@ -514,7 +514,7 @@ function validateMeatAddition(currentPizza: Bitflag, toppingsToAdd: Bitflag) { ]; ``` -
+
> [!TIP] > **Bit Position Visualization:** The `visual` field shows a 32-character representation where `[1]` indicates set bits and `0` shows unset bits. The format is `(0)[bit31][bit30]...[bit1][bit0]` with the sign bit always shown as `(0)`. @@ -528,8 +528,8 @@ function validateMeatAddition(currentPizza: Bitflag, toppingsToAdd: Bitflag) { - `.value` A getter that returns the current numeric value of the flags as a regular number. -
- Usage Examples +
+ Usage Examples ```ts bitflag(flags.READ | flags.WRITE).value; // returns 3 @@ -537,13 +537,13 @@ function validateMeatAddition(currentPizza: Bitflag, toppingsToAdd: Bitflag) { bitflag(flags.ALL).value; // returns the combined numeric value ``` -
+
- `.valueOf()` Returns the current numeric value of the flags, enabling implicit conversion to number in JavaScript operations. -
- Usage Examples +
+ Usage Examples ```ts bitflag(flags.READ).valueOf(); // explicit call @@ -551,13 +551,13 @@ function validateMeatAddition(currentPizza: Bitflag, toppingsToAdd: Bitflag) { Number(bitflag(flags.EXECUTE)); // explicit conversion ``` -
+
- `.toString()` Returns the string representation of the current numeric value of the flags. -
- Usage Examples +
+ Usage Examples ```ts bitflag(flags.READ).toString(); // returns "1" @@ -565,7 +565,7 @@ function validateMeatAddition(currentPizza: Bitflag, toppingsToAdd: Bitflag) { `Current flags: ${bitflag(flags.ALL)}`; // template literal usage ``` -
+
- `defineBitflags>(obj: T)` From 628a2bd44e698353b3c85c7209a927a1f636cde8 Mon Sep 17 00:00:00 2001 From: Igor Klepacki Date: Tue, 2 Sep 2025 04:58:28 +0200 Subject: [PATCH 2/2] fix: restructure readme to be more readable --- README.md | 858 +++++++++++++++++++++++++----------------------------- 1 file changed, 403 insertions(+), 455 deletions(-) diff --git a/README.md b/README.md index c3c9ebf..1e69247 100644 --- a/README.md +++ b/README.md @@ -126,31 +126,31 @@ function validateMeatAddition(currentPizza: Bitflag, toppingsToAdd: Bitflag) { **Core runtime functionality:** -- `bitflag` - the main function to perform bitwise operations on the flags. +- [`bitflag`](#bitflagbitflag--number) - the main function to perform bitwise operations on the flags. - Bitwise operations abstraction - - `has` - checks if the specified flags are set - - `hasAny` - checks if any of the specified flags are set - - `hasExact` - checks if the specified flags are set exactly - - `add` - adds the specified flags - - `remove` - removes the specified flags - - `toggle` - toggles the specified flags - - `clear` - clears all flags + - [`has`](#hasbitflag) - checks if the specified flags are set + - [`hasAny`](#hasanybitflag) - checks if any of the specified flags are set + - [`hasExact`](#hasexactbitflag) - checks if the specified flags are set exactly + - [`add`](#addbitflag) - adds the specified flags + - [`remove`](#removebitflag) - removes the specified flags + - [`toggle`](#togglebitflag) - toggles the specified flags + - [`clear`](#clear) - clears all flags - Debugging and visualization - - `describe` - returns an iterator for describing the flags + - [`describe`](#describeflagdefinitions-bitflagsdefinitionst) - returns an iterator for describing the flags - Interoperability between the library and other code - - `value` - returns the current value of the flags - - `valueOf` - returns the current value of the flags - - `toString` - returns the string representation of the flags -- `defineBitflags` - utility to define type-safe set of bit flags + - [`value`](#value) - returns the current value of the flags + - [`valueOf`](#valueof) - returns the current value of the flags + - [`toString`](#tostring) - returns the string representation of the flags +- [`defineBitflags`](#definebitflagst-extends-recordstring-numberobj-t) - utility to define type-safe set of bit flags > [!NOTE] > All of the operations support passing multiple flags at once through variadic arguments. **Utility functions** -- `makeBitflag` - utility to create a `Bitflag` Tagged Type from a number if it is possible. -- `isBitflag` - utility to check if number is within allowed range and to create a `Bitflag` Tagged type out of it -- `unwrapBitflag` - utility to unwrap the Tagged type of `Bitflag` to be just `number` +- [`makeBitflag`](#makebitflagvalue-number) - utility to create a `Bitflag` Tagged Type from a number if it is possible. +- [`isBitflag`](#isbitflagvalue-unknown) - utility to check if number is within allowed range and to create a `Bitflag` Tagged type out of it +- [`unwrapBitflag`](#unwrapbitflagflag-bitflag) - utility to unwrap the Tagged type of `Bitflag` to be just `number` **Type utilities** @@ -158,538 +158,486 @@ function validateMeatAddition(currentPizza: Bitflag, toppingsToAdd: Bitflag) { - `BitflagsDefinitions` - The type for frozen bitflag definition objects returned by `defineBitflags` - `InferBitflagsDefinitions` - Type utility to extract the shape from bitflag definitions (similar to Zod's `z.infer`) -## API Specifications - -- `bitflag(Bitflag | number)` - - Bitflag is a factory function that returns object with a specific set of operations for managing the flags. It accepts any number or `Bitflag` Tagged Type as an argument and then allows you to perform various operations on it. It also supports methods like `toString()`, `value` getter and `valueOf()` for compatibility with other JavaScript APIs. - -> [!IMPORTANT] -> -> The `bitflag` function's returned object's methods are **non-chainable** - each call to the bitwise operations returns just a number wrapped with the `Bitflag` Tagged Type. It does not return a new instance of the `bitflag` object. -> -> ✅ Good -> -> ```ts -> const combinedFlags = bitflag(flags.NONE).add( -> flags.MY_OTHER_FLAG, -> flags.ANOTHER_FLAG -> ); -> -> if (bitflag(combinedFlags).has(flags.ANOTHER_FLAG)) { -> console.log("has ANOTHER_FLAG"); -> } -> ``` -> -> ❌ Bad -> -> ```ts -> if ( -> bitflag(flags.NONE) -> .add(flags.MY_OTHER_FLAG, flags.ANOTHER_FLAG) -> .has(flags.ANOTHER_FLAG) -> ) { -> console.log("has ANOTHER_FLAG"); -> } -> ``` - -- `.add(...Bitflag[])` - Adds the specified flags to the current set. Returns a new number wrapped in `Bitflag` as the updated flags. +## API Reference -> [!TIP] -> Adding the same flag multiple times is idempotent - it won't change the result. +### `bitflag(Bitflag | number)` -
- Usage Examples +Bitflag is a factory function that returns object with a specific set of operations for managing the flags. It accepts any number or `Bitflag` Tagged Type as an argument and then allows you to perform various operations on it. It also supports methods like `toString()`, `value` getter and `valueOf()` for compatibility with other JavaScript APIs. - ```ts - bitflag(flags.MY_FLAG).add(flags.MY_OTHER_FLAG); // single defined - bitflag(flags.MY_FLAG).add(flags.MY_OTHER_FLAG, flags.ANOTHER_FLAG); // multiple defined - bitflag(flags.MY_FLAG).add(flags.MY_OTHER_FLAG, makeBitflag(1 << 2)); // mixed - ``` +**Important:** The `bitflag` function's returned object's methods are **non-chainable** - each call to the bitwise operations returns just a number wrapped with the `Bitflag` Tagged Type. It does not return a new instance of the `bitflag` object. -
+#### Correct Usage -- `.remove(...Bitflag[])` - Removes the specified flags from the current set. Returns a new number wrapped in `Bitflag` as the updated flags. +```ts +const combinedFlags = bitflag(flags.NONE).add( + flags.MY_OTHER_FLAG, + flags.ANOTHER_FLAG +); -> [!TIP] -> Removing non-existent flags has no effect and won't change the result. +if (bitflag(combinedFlags).has(flags.ANOTHER_FLAG)) { + console.log("has ANOTHER_FLAG"); +} +``` -
- Usage Examples +#### Incorrect Usage - ```ts - bitflag(flags.READ | flags.WRITE).remove(flags.WRITE); // single defined - bitflag(flags.ALL).remove(flags.WRITE, flags.DELETE); // multiple defined - bitflag(flags.READ | flags.WRITE).remove(flags.WRITE, makeBitflag(1 << 3)); // mixed - ``` +```ts +// ❌ This will not work as expected +if ( + bitflag(flags.NONE) + .add(flags.MY_OTHER_FLAG, flags.ANOTHER_FLAG) + .has(flags.ANOTHER_FLAG) +) { + console.log("has ANOTHER_FLAG"); +} +``` -
+### Bitwise Operations -- `.toggle(...Bitflag[])` - Toggles the specified flags in the current set - adds them if not present, removes them if present. Returns a new number wrapped in `Bitflag` as the updated flags. +### `.has(...Bitflag[])` -
- Usage Examples +Checks if all the specified flags are set in the current set. Returns `true` if all flags are present, `false` otherwise. - ```ts - bitflag(flags.READ).toggle(flags.WRITE); // single defined - bitflag(flags.READ | flags.EXECUTE).toggle(flags.WRITE, flags.EXECUTE); // multiple defined - bitflag(flags.READ).toggle(flags.WRITE, makeBitflag(1 << 4)); // mixed - ``` +**Tip:** Passing no arguments to `.has()` always returns `false`. -
+#### Examples -- `.has(...Bitflag[])` - Checks if all the specified flags are set in the current set. Returns `true` if all flags are present, `false` otherwise. +```ts +bitflag(flags.READ | flags.WRITE).has(flags.READ); // single defined +bitflag(flags.READ | flags.WRITE | flags.EXECUTE).has( + flags.READ, + flags.WRITE +); // multiple defined +bitflag(flags.READ | flags.WRITE).has(flags.READ, makeBitflag(1 << 1)); // mixed +``` -> [!TIP] -> Passing no arguments to `.has()` always returns `false`. +### `.hasAny(...Bitflag[])` -
- Usage Examples +Checks if any of the specified flags are set in the current set. Returns `true` if at least one flag is present, `false` if none are present. - ```ts - bitflag(flags.READ | flags.WRITE).has(flags.READ); // single defined - bitflag(flags.READ | flags.WRITE | flags.EXECUTE).has( - flags.READ, - flags.WRITE - ); // multiple defined - bitflag(flags.READ | flags.WRITE).has(flags.READ, makeBitflag(1 << 1)); // mixed - ``` - -
- -- `.hasAny(...Bitflag[])` - Checks if any of the specified flags are set in the current set. Returns `true` if at least one flag is present, `false` if none are present. - -> [!TIP] -> Passing no arguments to `.hasAny()` always returns `false`. - -
- Usage Examples - - ```ts - bitflag(flags.READ | flags.WRITE).hasAny(flags.EXECUTE); // single defined - bitflag(flags.READ).hasAny(flags.EXECUTE, flags.DELETE); // multiple defined - bitflag(flags.READ).hasAny(flags.EXECUTE, makeBitflag(1 << 0)); // mixed - ``` +**Tip:** Passing no arguments to `.hasAny()` always returns `false`. -
+#### Examples -- `.hasExact(...Bitflag[])` - Checks if the current set matches exactly the specified flags - no more, no less. Returns `true` if the flags match exactly, `false` otherwise. +```ts +bitflag(flags.READ | flags.WRITE).hasAny(flags.EXECUTE); // single defined +bitflag(flags.READ).hasAny(flags.EXECUTE, flags.DELETE); // multiple defined +bitflag(flags.READ).hasAny(flags.EXECUTE, makeBitflag(1 << 0)); // mixed +``` -> [!TIP] -> Calling `.hasExact()` with no arguments checks if the current value is exactly zero. +### `.hasExact(...Bitflag[])` -
- Usage Examples +Checks if the current set matches exactly the specified flags - no more, no less. Returns `true` if the flags match exactly, `false` otherwise. - ```ts - bitflag(flags.READ | flags.WRITE).hasExact(flags.READ, flags.WRITE); // single defined exact match - bitflag(flags.NONE).hasExact(); // multiple defined (empty means zero flags) - bitflag(flags.READ).hasExact(makeBitflag(1 << 0)); // mixed - ``` +**Tip:** Calling `.hasExact()` with no arguments checks if the current value is exactly zero. -
+#### Examples -- `.clear()` - Clears all flags, setting the value to zero. Returns a new number wrapped in `Bitflag` with value 0. +```ts +bitflag(flags.READ | flags.WRITE).hasExact(flags.READ, flags.WRITE); // single defined exact match +bitflag(flags.NONE).hasExact(); // multiple defined (empty means zero flags) +bitflag(flags.READ).hasExact(makeBitflag(1 << 0)); // mixed +``` -
- Usage Examples +### `.add(...Bitflag[])` - ```ts - bitflag(flags.ALL).clear(); // returns 0 as Bitflag - ``` +Adds the specified flags to the current set. Returns a new number wrapped in `Bitflag` as the updated flags. -
+**Tip:** Adding the same flag multiple times is idempotent - it won't change the result. -- `.describe(flagDefinitions?: BitflagsDefinitions)` - Returns an iterator that yields `FlagDescription` objects for each set bit, providing detailed information about the flags including name, value, and bit position visualization. +#### Examples - **FlagDescription Structure:** +```ts +bitflag(flags.MY_FLAG).add(flags.MY_OTHER_FLAG); // single defined +bitflag(flags.MY_FLAG).add(flags.MY_OTHER_FLAG, flags.ANOTHER_FLAG); // multiple defined +bitflag(flags.MY_FLAG).add(flags.MY_OTHER_FLAG, makeBitflag(1 << 2)); // mixed +``` - ```ts - type FlagDescription = { - name: string; // Flag name or "BIT_X"/"UNKNOWN_BIT_X" - value: number; // Numeric value of this specific flag - decimal: string; // Decimal representation (e.g., "42") - hexadecimal: string; // Hexadecimal with 0x prefix (e.g., "0x2A") - binary: string; // Binary with 0b prefix (e.g., "0b101010") - unknown: boolean; // true if flag not found in the definitions provided via parameter - bitPosition: { - exact: number; // Highest bit position (-1 for zero) - remaining: number; // Remaining available bit positions - visual: string; // Visual bit representation with [1] markers - }; +### `.remove(...Bitflag[])` + +Removes the specified flags from the current set. Returns a new number wrapped in `Bitflag` as the updated flags. + +**Tip:** Removing non-existent flags has no effect and won't change the result. + +#### Examples + +```ts +bitflag(flags.READ | flags.WRITE).remove(flags.WRITE); // single defined +bitflag(flags.ALL).remove(flags.WRITE, flags.DELETE); // multiple defined +bitflag(flags.READ | flags.WRITE).remove(flags.WRITE, makeBitflag(1 << 3)); // mixed +``` + +### `.toggle(...Bitflag[])` + +Toggles the specified flags in the current set - adds them if not present, removes them if present. Returns a new number wrapped in `Bitflag` as the updated flags. + +#### Examples + +```ts +bitflag(flags.READ).toggle(flags.WRITE); // single defined +bitflag(flags.READ | flags.EXECUTE).toggle(flags.WRITE, flags.EXECUTE); // multiple defined +bitflag(flags.read).toggle(flags.WRITE, makeBitflag(1 << 4)); // mixed +``` + +### `.clear()` + +Clears all flags, setting the value to zero. Returns a new number wrapped in `Bitflag` with value 0. + +#### Examples + +```ts +bitflag(flags.ALL).clear(); // returns 0 as Bitflag +``` + +### Debugging and Visualization + +### `.describe(flagDefinitions?: BitflagsDefinitions)` + +Returns an iterator that yields `FlagDescription` objects for each set bit, providing detailed information about the flags including name, value, and bit position visualization. + +#### FlagDescription Structure + +```ts +type FlagDescription = { + name: string; // Flag name or "BIT_X"/"UNKNOWN_BIT_X" + value: number; // Numeric value of this specific flag + decimal: string; // Decimal representation (e.g., "42") + hexadecimal: string; // Hexadecimal with 0x prefix (e.g., "0x2A") + binary: string; // Binary with 0b prefix (e.g., "0b101010") + unknown: boolean; // true if flag not found in the definitions provided via parameter + bitPosition: { + exact: number; // Highest bit position (-1 for zero) + remaining: number; // Remaining available bit positions + visual: string; // Visual bit representation with [1] markers }; - ``` - - Examples: - -
- Basic Usage with Flag Definitions - - ```ts - [...bitflag(flags.READ | flags.WRITE).describe(flags)]; - ``` - - ```js - // Returns: - [ - { - name: "READ", - value: 1, - decimal: "1", - hexadecimal: "0x1", - binary: "0b1", - unknown: false, - bitPosition: { - exact: 0, - remaining: 31, - visual: "(0)000000000000000000000000000000[1]", - }, - }, - { - name: "WRITE", - value: 2, - decimal: "2", - hexadecimal: "0x2", - binary: "0b10", - unknown: false, - bitPosition: { - exact: 1, - remaining: 30, - visual: "(0)00000000000000000000000000000[1]0", - }, - }, - ]; - ``` - -
- -
- Generic Bit Names (No Definitions) - - ```ts - // Without definitions - shows generic BIT_X names - [...bitflag(5).describe()]; // value 5 = bits 0 and 2 - ``` - - ```js - // Returns: - [ - { - name: "BIT_0", - value: 1, - binary: "0b1", - unknown: false, - bitPosition: { - exact: 0, - remaining: 31, - visual: "(0)000000000000000000000000000000[1]", - }, - }, - { - name: "BIT_2", - value: 4, - binary: "0b100", - unknown: false, - bitPosition: { - exact: 2, - remaining: 29, - visual: "(0)0000000000000000000000000000[1]00", - }, +}; +``` + +#### Examples + +**Basic Usage with Flag Definitions** + +```ts +[...bitflag(flags.READ | flags.WRITE).describe(flags)]; +``` + +Returns: +```js +[ + { + name: "READ", + value: 1, + decimal: "1", + hexadecimal: "0x1", + binary: "0b1", + unknown: false, + bitPosition: { + exact: 0, + remaining: 31, + visual: "(0)000000000000000000000000000000[1]", }, - ]; - ``` - -
- -
- Mixed Known and Unknown Flags - - ```ts - // Mixed known and unknown flags - [...bitflag(flags.READ | makeBitflag(1 << 10)).describe(flags)]; - ``` - - ```js - // Returns: - [ - { - name: "READ", - value: 1, - decimal: "1", - hexadecimal: "0x1", - binary: "0b1", - unknown: false, - bitPosition: { - exact: 0, - remaining: 31, - visual: "(0)000000000000000000000000000000[1]", - }, + }, + { + name: "WRITE", + value: 2, + decimal: "2", + hexadecimal: "0x2", + binary: "0b10", + unknown: false, + bitPosition: { + exact: 1, + remaining: 30, + visual: "(0)00000000000000000000000000000[1]0", }, - { - name: "UNKNOWN_BIT_10", - value: 1024, - decimal: "1024", - hexadecimal: "0x400", - binary: "0b10000000000", - unknown: true, - bitPosition: { - exact: 10, - remaining: 21, - visual: "(0)00000000000000000000[1]0000000000", - }, + }, +] +``` + +**Generic Bit Names (No Definitions)** + +```ts +// Without definitions - shows generic BIT_X names +[...bitflag(5).describe()]; // value 5 = bits 0 and 2 +``` + +Returns: +```js +[ + { + name: "BIT_0", + value: 1, + binary: "0b1", + unknown: false, + bitPosition: { + exact: 0, + remaining: 31, + visual: "(0)000000000000000000000000000000[1]", }, - ]; - ``` - -
- -
- Zero Value Special Case - - ```ts - // Zero value special case - [...bitflag(0).describe()]; - ``` - - ```js - // Returns: - [ - { - name: "NONE", - value: 0, - decimal: "0", - hexadecimal: "0x0", - binary: "0b0", - unknown: false, - bitPosition: { - exact: -1, - remaining: 31, - visual: "(0)0000000000000000000000000000000", - }, + }, + { + name: "BIT_2", + value: 4, + binary: "0b100", + unknown: false, + bitPosition: { + exact: 2, + remaining: 29, + visual: "(0)0000000000000000000000000000[1]00", }, - ]; - ``` - -
- -
- High Bit Positions (15 & 30) - - ```ts - // High bit positions (bit 15 and 30) - [...bitflag(makeBitflag((1 << 15) | (1 << 30))).describe()]; - ``` - - ```js - // Returns: - [ - { - name: "BIT_15", - value: 32768, - binary: "0b1000000000000000", - bitPosition: { - exact: 15, - remaining: 16, - visual: "(0)000000000000000[1]000000000000000", - }, + }, +] +``` + +**Mixed Known and Unknown Flags** + +```ts +// Mixed known and unknown flags +[...bitflag(flags.READ | makeBitflag(1 << 10)).describe(flags)]; +``` + +Returns: +```js +[ + { + name: "READ", + value: 1, + decimal: "1", + hexadecimal: "0x1", + binary: "0b1", + unknown: false, + bitPosition: { + exact: 0, + remaining: 31, + visual: "(0)000000000000000000000000000000[1]", }, - { - name: "BIT_30", - value: 1073741824, - binary: "0b1000000000000000000000000000000", - bitPosition: { - exact: 30, - remaining: 1, - visual: "(0)[1]000000000000000000000000000000", - }, + }, + { + name: "UNKNOWN_BIT_10", + value: 1024, + decimal: "1024", + hexadecimal: "0x400", + binary: "0b10000000000", + unknown: true, + bitPosition: { + exact: 10, + remaining: 21, + visual: "(0)00000000000000000000[1]0000000000", }, - ]; - ``` + }, +] +``` -
+**Zero Value Special Case** -> [!TIP] -> **Bit Position Visualization:** The `visual` field shows a 32-character representation where `[1]` indicates set bits and `0` shows unset bits. The format is `(0)[bit31][bit30]...[bit1][bit0]` with the sign bit always shown as `(0)`. +```ts +// Zero value special case +[...bitflag(0).describe()]; +``` -> [!TIP] -> **Flag Resolution Order:** When using flag definitions, the iterator yields known flags first (in the order they match), then unknown bits as `UNKNOWN_BIT_X` in ascending bit order. +Returns: +```js +[ + { + name: "NONE", + value: 0, + decimal: "0", + hexadecimal: "0x0", + binary: "0b0", + unknown: false, + bitPosition: { + exact: -1, + remaining: 31, + visual: "(0)0000000000000000000000000000000", + }, + }, +] +``` -> [!TIP] -> **Complex Flags:** Combined flags (like `READ_WRITE: (1<<0)|(1<<1)`) are detected when their exact bit pattern matches the current value, alongside their individual component flags. +**High Bit Positions (15 & 30)** -- `.value` - A getter that returns the current numeric value of the flags as a regular number. +```ts +// High bit positions (bit 15 and 30) +[...bitflag(makeBitflag((1 << 15) | (1 << 30))).describe()]; +``` -
- Usage Examples +Returns: +```js +[ + { + name: "BIT_15", + value: 32768, + binary: "0b1000000000000000", + bitPosition: { + exact: 15, + remaining: 16, + visual: "(0)000000000000000[1]000000000000000", + }, + }, + { + name: "BIT_30", + value: 1073741824, + binary: "0b1000000000000000000000000000000", + bitPosition: { + exact: 30, + remaining: 1, + visual: "(0)[1]000000000000000000000000000000", + }, + }, +] +``` - ```ts - bitflag(flags.READ | flags.WRITE).value; // returns 3 - bitflag().value; // returns 0 - bitflag(flags.ALL).value; // returns the combined numeric value - ``` +#### Important Notes -
+**Bit Position Visualization:** The `visual` field shows a 32-character representation where `[1]` indicates set bits and `0` shows unset bits. The format is `(0)[bit31][bit30]...[bit1][bit0]` with the sign bit always shown as `(0)`. -- `.valueOf()` - Returns the current numeric value of the flags, enabling implicit conversion to number in JavaScript operations. +**Flag Resolution Order:** When using flag definitions, the iterator yields known flags first (in the order they match), then unknown bits as `UNKNOWN_BIT_X` in ascending bit order. -
- Usage Examples +**Complex Flags:** Combined flags (like `READ_WRITE: (1<<0)|(1<<1)`) are detected when their exact bit pattern matches the current value, alongside their individual component flags. - ```ts - bitflag(flags.READ).valueOf(); // explicit call - +bitflag(flags.WRITE); // implicit conversion - Number(bitflag(flags.EXECUTE)); // explicit conversion - ``` +### Interoperability between the library and other code -
+### `.value` -- `.toString()` - Returns the string representation of the current numeric value of the flags. +A getter that returns the current numeric value of the flags as a regular number. -
- Usage Examples +#### Examples - ```ts - bitflag(flags.READ).toString(); // returns "1" - String(bitflag(flags.READ | flags.WRITE)); // returns "3" - `Current flags: ${bitflag(flags.ALL)}`; // template literal usage - ``` +```ts +bitflag(flags.READ | flags.WRITE).value; // returns 3 +bitflag().value; // returns 0 +bitflag(flags.ALL).value; // returns the combined numeric value +``` -
+### `.valueOf()` -- `defineBitflags>(obj: T)` +Returns the current numeric value of the flags, enabling implicit conversion to number in JavaScript operations. - Utility function to define a type-safe set of bit flags. It validates that all values are non-negative integers within the 31-bit range and returns a frozen object with `Bitflag` Tagged Types. +#### Examples -
- Usage Examples +```ts +bitflag(flags.READ).valueOf(); // explicit call ++bitflag(flags.WRITE); // implicit conversion +Number(bitflag(flags.EXECUTE)); // explicit conversion +``` - ```ts - const flags = defineBitflags({ - READ: 1 << 0, - WRITE: 1 << 1, - EXECUTE: 1 << 2, - }); // basic usage +### `.toString()` - const complexFlags = defineBitflags({ - NONE: 0, - READ: 1 << 0, - WRITE: 1 << 1, - READ_WRITE: (1 << 0) | (1 << 1), - }); // with combined flags +Returns the string representation of the current numeric value of the flags. - const permissions = defineBitflags({ - VIEWER: 1, - EDITOR: 3, - ADMIN: 15, - }); // with arbitrary values - ``` +#### Examples -
+```ts +bitflag(flags.READ).toString(); // returns "1" +String(bitflag(flags.READ | flags.WRITE)); // returns "3" +`Current flags: ${bitflag(flags.ALL)}`; // template literal usage +``` -> [!TIP] -> The returned object is frozen to prevent accidental modifications. All values must be within the range 0 to 0x7FFFFFFF (31-bit signed integer range). +### Utility Functions -- `makeBitflag(value: number)` +### `defineBitflags>(obj: T)` - Utility function to create a `Bitflag` Tagged Type from a number if it's within the valid range. Throws an error if the conversion would result in a data loss. +Utility function to define a type-safe set of bit flags. It validates that all values are non-negative integers within the 31-bit range and returns a frozen object with `Bitflag` Tagged Types. -
- Usage Examples +**Tip:** The returned object is frozen to prevent accidental modifications. All values must be within the range 0 to 0x7FFFFFFF (31-bit signed integer range). - ```ts - makeBitflag(5); // creates Bitflag from valid number - makeBitflag(0); // creates Bitflag for zero - makeBitflag(0x7fffffff); // creates Bitflag for maximum value - ``` +#### Examples -
+```ts +const flags = defineBitflags({ + READ: 1 << 0, + WRITE: 1 << 1, + EXECUTE: 1 << 2, +}); // basic usage + +const complexFlags = defineBitflags({ + NONE: 0, + READ: 1 << 0, + WRITE: 1 << 1, + READ_WRITE: (1 << 0) | (1 << 1), +}); // with combined flags + +const permissions = defineBitflags({ + VIEWER: 1, + EDITOR: 3, + ADMIN: 15, +}); // with arbitrary values +``` -> [!TIP] -> This function validates the input and throws a descriptive error for invalid values (negative numbers or values exceeding 31 bits). It is also the only function that `throws` +### `makeBitflag(value: number)` -- `isBitflag(value: unknown)` +Utility function to create a `Bitflag` Tagged Type from a number if it's within the valid range. Throws an error if the conversion would result in a data loss. - Type guard utility to check if a value can be used as a `Bitflag`. Returns `true` if the value is a non-negative integer within the 31-bit range. +**Tip:** This function validates the input and throws a descriptive error for invalid values (negative numbers or values exceeding 31 bits). It is also the only function that throws. -
- Usage Examples +#### Examples - ```ts - isBitflag(5); // returns true - isBitflag(-1); // returns false - isBitflag(1.5); // returns false - ``` +```ts +makeBitflag(5); // creates Bitflag from valid number +makeBitflag(0); // creates Bitflag for zero +makeBitflag(0x7fffffff); // creates Bitflag for maximum value +``` -
+### `isBitflag(value: unknown)` -> [!TIP] -> This function is useful for runtime validation before using values with the bitflag operations. +Type guard utility to check if a value can be used as a `Bitflag`. Returns `true` if the value is a non-negative integer within the 31-bit range. -- `unwrapBitflag(flag: Bitflag)` +**Tip:** This function is useful for runtime validation before using values with the bitflag operations. - Utility function to extract the numeric value from a `Bitflag` Tagged Type, converting it back to a regular number. +#### Examples -
- Usage Examples +```ts +isBitflag(5); // returns true +isBitflag(-1); // returns false +isBitflag(1.5); // returns false +``` - ```ts - const flags = defineBitflags({ TEST: 5 }); - unwrapBitflag(flags.TEST); // returns 5 as number - unwrapBitflag(bitflag(flags.TEST).add(makeBitflag(2))); // returns 7 as number - unwrapBitflag(bitflag().clear());// returns 0 as number - ``` +### `unwrapBitflag(flag: Bitflag)` -
+Utility function to extract the numeric value from a `Bitflag` Tagged Type, converting it back to a regular number. -## Type Utilities +#### Examples -- `Bitflag` +```ts +const flags = defineBitflags({ TEST: 5 }); +unwrapBitflag(flags.TEST); // returns 5 as number +unwrapBitflag(bitflag(flags.TEST).add(makeBitflag(2))); // returns 7 as number +unwrapBitflag(bitflag().clear()); // returns 0 as number +``` - The tagged type for individual bitflag numbers. This ensures type safety by distinguishing bitflag numbers from regular numbers. +### Type Utilities - It is mostly used internally inside the library source. Export exists for complex cases where you would need this type. +### `Bitflag` -- `BitflagsDefinitions` +The tagged type for individual bitflag numbers. This ensures type safety by distinguishing bitflag numbers from regular numbers. - The type for frozen bitflag definition objects returned by `defineBitflags`. This represents the complete set of flag definitions. +It is mostly used internally inside the library source. Export exists for complex cases where you would need this type. - It is mostly used internally inside the library source. Export exists for complex cases where you would need this type. +### `BitflagsDefinitions` +The type for frozen bitflag definition objects returned by `defineBitflags`. This represents the complete set of flag definitions. -- `InferBitflagsDefinitions` +It is mostly used internally inside the library source. Export exists for complex cases where you would need this type. - Type utility to extract the shape from bitflag definitions. Converts `BitflagsDefinitions` to `Record`. +### `InferBitflagsDefinitions` -
- Usage Examples +Type utility to extract the shape from bitflag definitions. Converts `BitflagsDefinitions` to `Record`. - ```ts - import { type InferBitflagsDefinitions } from "bitf"; +#### Examples - // Define flags - const UserPermissions = defineBitflags({ - READ: 1 << 0, - WRITE: 1 << 1, - DELETE: 1 << 2, - }); +```ts +import { type InferBitflagsDefinitions } from "bitf"; - // Extract type shape - type UserPermissionsType = InferBitflagsDefinitions; - // Result: { READ: Bitflag; WRITE: Bitflag; DELETE: Bitflag } - ``` +// Define flags +const UserPermissions = defineBitflags({ + READ: 1 << 0, + WRITE: 1 << 1, + DELETE: 1 << 2, +}); -
+// Extract type shape +type UserPermissionsType = InferBitflagsDefinitions; +// Result: { READ: Bitflag; WRITE: Bitflag; DELETE: Bitflag } +``` ## Benchmarks