|
48 | 48 | from immutabledict import immutabledict |
49 | 49 | from signedjson.key import decode_verify_key_bytes |
50 | 50 | from signedjson.types import VerifyKey |
51 | | -from typing_extensions import TypedDict |
| 51 | +from typing_extensions import Self, TypedDict |
52 | 52 | from unpaddedbase64 import decode_base64 |
53 | 53 | from zope.interface import Interface |
54 | 54 |
|
@@ -515,6 +515,27 @@ def get_stream_pos_for_instance(self, instance_name: str) -> int: |
515 | 515 | # at `self.stream`. |
516 | 516 | return self.instance_map.get(instance_name, self.stream) |
517 | 517 |
|
| 518 | + def is_before_or_eq(self, other_token: Self) -> bool: |
| 519 | + """Wether this token is before the other token, i.e. every constituent |
| 520 | + part is before the other. |
| 521 | +
|
| 522 | + Essentially it is `self <= other`. |
| 523 | +
|
| 524 | + Note: if `self.is_before_or_eq(other_token) is False` then that does not |
| 525 | + imply that the reverse is True. |
| 526 | + """ |
| 527 | + if self.stream > other_token.stream: |
| 528 | + return False |
| 529 | + |
| 530 | + instances = self.instance_map.keys() | other_token.instance_map.keys() |
| 531 | + for instance in instances: |
| 532 | + if self.instance_map.get( |
| 533 | + instance, self.stream |
| 534 | + ) > other_token.instance_map.get(instance, other_token.stream): |
| 535 | + return False |
| 536 | + |
| 537 | + return True |
| 538 | + |
518 | 539 |
|
519 | 540 | @attr.s(frozen=True, slots=True, order=False) |
520 | 541 | class RoomStreamToken(AbstractMultiWriterStreamToken): |
@@ -1008,6 +1029,41 @@ def get_field( |
1008 | 1029 | """Returns the stream ID for the given key.""" |
1009 | 1030 | return getattr(self, key.value) |
1010 | 1031 |
|
| 1032 | + def is_before_or_eq(self, other_token: "StreamToken") -> bool: |
| 1033 | + """Wether this token is before the other token, i.e. every constituent |
| 1034 | + part is before the other. |
| 1035 | +
|
| 1036 | + Essentially it is `self <= other`. |
| 1037 | +
|
| 1038 | + Note: if `self.is_before_or_eq(other_token) is False` then that does not |
| 1039 | + imply that the reverse is True. |
| 1040 | + """ |
| 1041 | + |
| 1042 | + for _, key in StreamKeyType.__members__.items(): |
| 1043 | + if key == StreamKeyType.TYPING: |
| 1044 | + # Typing stream is allowed to "reset", and so comparisons don't |
| 1045 | + # really make sense as is. |
| 1046 | + # TODO: Figure out a better way of tracking resets. |
| 1047 | + continue |
| 1048 | + |
| 1049 | + self_value = self.get_field(key) |
| 1050 | + other_value = other_token.get_field(key) |
| 1051 | + |
| 1052 | + if isinstance(self_value, RoomStreamToken): |
| 1053 | + assert isinstance(other_value, RoomStreamToken) |
| 1054 | + if not self_value.is_before_or_eq(other_value): |
| 1055 | + return False |
| 1056 | + elif isinstance(self_value, MultiWriterStreamToken): |
| 1057 | + assert isinstance(other_value, MultiWriterStreamToken) |
| 1058 | + if not self_value.is_before_or_eq(other_value): |
| 1059 | + return False |
| 1060 | + else: |
| 1061 | + assert isinstance(other_value, int) |
| 1062 | + if self_value > other_value: |
| 1063 | + return False |
| 1064 | + |
| 1065 | + return True |
| 1066 | + |
1011 | 1067 |
|
1012 | 1068 | StreamToken.START = StreamToken( |
1013 | 1069 | RoomStreamToken(stream=0), 0, 0, MultiWriterStreamToken(stream=0), 0, 0, 0, 0, 0, 0 |
|
0 commit comments