Skip to content

Commit

Permalink
Improve handling of ArrayFlags
Browse files Browse the repository at this point in the history
Why discord did it this way instead of as an integer bitfield like everything reasonable is unknowable, but this does less work to get to the same result.

Add comment detailing what many would find unreadbale
  • Loading branch information
mikeshardmind committed Apr 18, 2023
1 parent 50f7b94 commit 1ef6043
Showing 1 changed file with 10 additions and 1 deletion.
11 changes: 10 additions & 1 deletion discord/flags.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
from __future__ import annotations

from functools import reduce
from operator import or_
from typing import TYPE_CHECKING, Any, Callable, ClassVar, Dict, Iterator, List, Optional, Tuple, Type, TypeVar, overload

from .enums import UserFlags
Expand Down Expand Up @@ -1566,7 +1567,15 @@ class ArrayFlags(BaseFlags):
@classmethod
def _from_value(cls: Type[Self], value: List[int]) -> Self:
self = cls.__new__(cls)
self.value = reduce(lambda a, b: a | (1 << b - 1), value, 0)
# This is a micro-optimization given the frequency this object can be created.
# (1).__lshift__ is used in place of lambda x: 1 << x
# prebinding to a method of a constant rather than define a lambda.
# Pairing this with map, is essentially equivalent to (1 << x for x in value)
# reduction using operator.or_ instead of defining a lambda each call
# Discord sends these starting with a value of 1
# Rather than subtract 1 from each element prior to left shift,
# we shift right by 1 once at the end.
self.value = reduce(or_, map((1).__lshift__, value), 0) >> 1
return self

def to_array(self) -> List[int]:
Expand Down

0 comments on commit 1ef6043

Please sign in to comment.