Skip to content

Commit

Permalink
Add factory methods to create an enum bit mask
Browse files Browse the repository at this point in the history
* Add a method to create a bit mask using one or multiple cases
* Add a method to create a bit mask using all cases
* Add a method to create a bit mask with no flags on
* Add a method to create a bit mask without some flags
  • Loading branch information
gisostallenberg committed Jun 11, 2024
1 parent 3072607 commit 35d40b2
Show file tree
Hide file tree
Showing 2 changed files with 114 additions and 7 deletions.
81 changes: 74 additions & 7 deletions src/EnumBitMask.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@
final class EnumBitMask implements BitMaskInterface
{
private BitMask $bitmask;
/** @var array<string, int> $map case => bit */

/**
* @var array<string, int> $map case => bit
*/
private array $map = [];

/**
Expand All @@ -33,26 +36,88 @@ public function __construct(
$this->bitmask = new BitMask($mask, count($this->enum::cases()) - 1);
}

/**
* Create an instance with given flags on
*
* @param class-string $enum
*
* @return static
*/
public static function create(string $enum, UnitEnum ...$bits): static
{
return (new static($enum))->set(...$bits);
}

/**
* Create an instance with all flags on
*
* @param class-string $enum
*
* @return static
*/
public static function all(string $enum): static
{
return self::create($enum, ...$enum::cases());
}

/**
* Create an instance with no flags on
*
* @param class-string $enum
*
* @return static
*/
public static function none(string $enum): static
{
return self::create($enum);
}

/**
* Create an instance without given flags on
*
* @param class-string $enum
*
* @return static
*/
public static function without(string $enum, UnitEnum ...$bits): static
{
return self::all($enum)->remove(...$bits);
}

public function get(): int
{
return $this->bitmask->get();
}

/** @throws UnknownEnumException|NotSingleBitException */
public function set(UnitEnum ...$bits): void
/**
* @throws UnknownEnumException|NotSingleBitException
*
* @return $this
*/
public function set(UnitEnum ...$bits): self
{
$this->has(...$bits);
$this->bitmask->set(...$this->enumToInt(...$bits));

return $this;
}

/** @throws UnknownEnumException|NotSingleBitException */
public function remove(UnitEnum ...$bits): void
/**
* @throws UnknownEnumException|NotSingleBitException
*
* @return $this
*/
public function remove(UnitEnum ...$bits): self
{
$this->has(...$bits);
$this->bitmask->remove(...$this->enumToInt(...$bits));

return $this;
}

/** @throws UnknownEnumException|NotSingleBitException */
/**
* @throws UnknownEnumException|NotSingleBitException
*/
public function has(UnitEnum ...$bits): bool
{
array_walk(
Expand All @@ -65,7 +130,9 @@ public function has(UnitEnum ...$bits): bool
return $this->bitmask->has(...$this->enumToInt(...$bits));
}

/** @return int[] */
/**
* @return int[]
*/
private function enumToInt(UnitEnum ...$bits): array
{
return array_map(fn(UnitEnum $bit) => $this->map[$bit->name], $bits);
Expand Down
40 changes: 40 additions & 0 deletions tests/EnumBitMaskTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -100,4 +100,44 @@ public function testBackedEnum(): void
assertFalse($backedIntEnumBitmask->has(BackedInt::Create, BackedInt::Read));
assertTrue($backedIntEnumBitmask->has(BackedInt::Update, BackedInt::Delete));
}

public function testCreateFactory(): void
{
$enumBitmask = EnumBitMask::create(Permissions::class);
assertSame(0, $enumBitmask->get());

$enumBitmask = EnumBitMask::create(Permissions::class, Permissions::Create);
assertSame(1, $enumBitmask->get());

$enumBitmask = EnumBitMask::create(Permissions::class, Permissions::Delete);
assertSame(8, $enumBitmask->get());

$enumBitmask = EnumBitMask::create(Permissions::class, Permissions::Delete, Permissions::Create);
assertSame(9, $enumBitmask->get());

$enumBitmask = EnumBitMask::create(Permissions::class, Permissions::Create, Permissions::Delete);
assertSame(9, $enumBitmask->get());


$this->expectException(UnknownEnumException::class);
EnumBitMask::create(Permissions::class, Unknown::Case);
}

public function testNoneFactory(): void
{
$enumBitmask = EnumBitMask::none(Permissions::class);
assertSame(0, $enumBitmask->get());
}

public function testAllFactory(): void
{
$enumBitmask = EnumBitMask::all(Permissions::class);
assertSame(15, $enumBitmask->get());
}

public function testWithoutFactory(): void
{
$enumBitmask = EnumBitMask::without(Permissions::class, Permissions::Delete);
assertSame(7, $enumBitmask->get());
}
}

0 comments on commit 35d40b2

Please sign in to comment.