from enum import Enum, auto
from getpass import getuser
from threading import Thread
-from typing import Any, Callable, Generic, NamedTuple, Optional, Self, TypeVar
+from typing import (Any, Callable, Collection, Generic, Iterator, NamedTuple,
+ Optional, Self, TypeVar)
from uuid import uuid4
# ourselves
from ircplom.events import (
class _Completable(ABC):
+ _completed: Any
@abstractmethod
def complete(self) -> None:
- 'Set .completed to "complete" value if possible of current state.'
+ 'Set ._completed to "complete" value if possible of current state.'
-class _CompletableStringsList(_Clearable, _Completable):
+class _CompletableStringsCollection(_Completable, Collection):
+ _collected: Collection[str]
+ _completed: Optional[Collection[str]] = None
- def __init__(self) -> None:
- self._incomplete: list[str] = []
- self.completed: tuple[str, ...] = tuple()
+ @abstractmethod
+ def _copy_collected(self) -> Collection[str]:
+ pass
+
+ def complete(self) -> None:
+ self._completed = self._copy_collected()
+
+ def __len__(self) -> int:
+ assert self._completed is not None
+ return len(self._completed)
+
+ def __contains__(self, item) -> bool:
+ assert self._completed is not None
+ assert isinstance(item, str)
+ return item in self._completed
+
+ def __iter__(self) -> Iterator[str]:
+ assert self._completed is not None
+ yield from self._completed
- def _on_list(self, m_name: str, value: str, complete: bool) -> None:
- getattr(self._incomplete, m_name)(value)
- if complete:
- self.complete()
+
+class _CompletableStringsOrdered(_Clearable, _CompletableStringsCollection):
+ _collected: tuple[str, ...] = tuple()
+ _completed: Optional[tuple[str, ...]] = None
+
+ def _copy_collected(self) -> tuple[str, ...]:
+ return tuple(self._collected)
def append(self, value: str, complete=False) -> None:
'Append value to list.'
- self._on_list('append', value, complete)
+ self._collected += (value,)
+ if complete:
+ self.complete()
def remove(self, value: str, complete=False) -> None:
'Remove value from list.'
- self._on_list('remove', value, complete)
-
- def complete(self) -> None:
- self.completed = tuple(self._incomplete)
+ assert value in self._collected
+ self._collected = tuple(x for x in self._collected if x != value)
+ if complete:
+ self.complete()
def clear(self) -> None:
- self._incomplete.clear()
- self.complete()
+ self._completed = None
+ self._collected = tuple()
+
+ def into_set(self) -> set[str]:
+ 'Return as mere set.'
+ assert self._completed is not None
+ return set(self._completed)
class IntoUpdateValueMixin(AutoAttrMixin):
'Return non-updating copy of self.'
if isinstance(self, _Dict):
return None
- if isinstance(self, _CompletableStringsList):
- return self.completed
+ if isinstance(self, _CompletableStringsOrdered):
+ return self._completed
if isinstance(self, _CompletableTopic):
- return Topic(*self.completed)
+ return Topic(*self._completed)
for cls in [cls for cls in self.__class__.__mro__
if AutoAttrMixin not in cls.__mro__]:
obj = cls()
self._on_update()
-class _UpdatingCompletableStringsList(_UpdatingCompletable,
- _CompletableStringsList):
+class _UpdatingCompletableStringsOrdered(_UpdatingCompletable,
+ _CompletableStringsOrdered):
pass
_who: Optional[NickUserHost] = None
def __init__(self) -> None:
- self.completed: tuple[str, Optional[NickUserHost]] = ('', None)
+ self._completed: tuple[str, Optional[NickUserHost]] = ('', None)
@property
def what(self) -> str:
self._who = NickUserHost(copy.nick, copy.user, copy.host)
def complete(self) -> None:
- self.completed = (('', None) if self._who is None
- else (self._what, self._who))
+ self._completed = (('', None) if self._who is None
+ else (self._what, self._who))
class _Channel:
- user_ids: _CompletableStringsList
+ user_ids: _CompletableStringsOrdered
topic: _CompletableTopic
def __init__(self,
class _UpdatingChannel(_UpdatingMixin, _Channel):
- user_ids: _UpdatingCompletableStringsList
+ user_ids: _UpdatingCompletableStringsOrdered
topic: _UpdatingCompletableTopic
class _UpdatingChannelsDict(_UpdatingDict[_UpdatingChannel]):
def _of_user(self, user: _User) -> dict[str, _UpdatingChannel]:
- return {k: v for k, v in self._dict.items()
- if user.id_ in v.user_ids.completed}
+ return {k: v for k, v in self._dict.items() if user.id_ in v.user_ids}
def of_user(self, user: _User) -> tuple[str, ...]:
'Return names of channels listing user as member.'
caps: _UpdatingDict[_UpdatingServerCapability]
channels: _UpdatingChannelsDict
isupport: _UpdatingDict[str]
- motd: _UpdatingCompletableStringsList
+ motd: _UpdatingCompletableStringsOrdered
users: _UpdatingUsersDict
def __getattribute__(self, key: str):
def clear(self) -> None:
self._dict.clear()
- self._ls = _CompletableStringsList()
- self._list = _CompletableStringsList()
+ self._ls = _CompletableStringsOrdered()
+ self._list = _CompletableStringsOrdered()
self._list_expectations: dict[str, set[str]] = {
'ACK': set(), 'NAK': set()}
elif target == self._list:
acks = self._list_expectations['ACK']
naks = self._list_expectations['NAK']
- list_set = set(target.completed)
+ list_set = target.into_set()
assert acks == list_set & acks
assert set() == list_set & naks
for key, data in [_Dict.key_val_from_eq_str(entry)
- for entry in self._ls.completed]:
+ for entry in self._ls]:
self._dict[key].data = data
- self._dict[key].enabled = key in self._list.completed
+ self._dict[key].enabled = key in self._list
return True
return False