from typing import Generic, Iterable, TypeVar from rainbowadn.hashing.hash_point_format import hash_point_format from rainbowadn.hashing.hashpoint import HashPoint from rainbowadn.hashing.hashresolver import HashResolver from rainbowadn.hashing.nullability.notnull import NotNull from rainbowadn.hashing.nullability.null import Null from rainbowadn.hashing.nullability.nullable import Nullable from rainbowadn.hashing.rainbow_factory import RainbowFactory from rainbowadn.hashing.recursivementionable import RecursiveMentionable from rainbowadn.hashing.resolverorigin import ResolverOrigin __all__ = ('NullableReference', 'NullableReferenceFactory',) ReferencedType = TypeVar('ReferencedType') class NullableReference(RecursiveMentionable, Generic[ReferencedType]): def __factory__(self) -> RainbowFactory['NullableReference[ReferencedType]']: return NullableReferenceFactory(self.factory) def points(self) -> Iterable[HashPoint]: if isinstance(self.reference, NotNull): return [self.reference.value] elif isinstance(self.reference, Null): return [] else: raise TypeError def __bytes__(self): if isinstance(self.reference, NotNull): hash_point: HashPoint[ReferencedType] = self.reference.value assert isinstance(hash_point, HashPoint) return hash_point.point elif isinstance(self.reference, Null): return HashPoint.NULL_HASH else: raise TypeError def __init__( self, reference: Nullable[HashPoint[ReferencedType]], factory: RainbowFactory[ReferencedType] ): assert isinstance(reference, Nullable) assert isinstance(factory, RainbowFactory) self.reference = reference self.factory = factory @classmethod def of(cls, hash_point: HashPoint[ReferencedType]) -> 'NullableReference[ReferencedType]': assert isinstance(hash_point, HashPoint) return cls(NotNull(hash_point), hash_point.factory) @classmethod def off(cls, value: ReferencedType) -> 'NullableReference[ReferencedType]': return cls.of(HashPoint.of(value)) def str(self, tab: int) -> str: if isinstance(self.reference, Null): return f'-' elif isinstance(self.reference, NotNull): return f'{hash_point_format(self.reference.value, tab)}' else: raise TypeError def __eq__(self, other): if isinstance(other, NullableReference): return self.reference == other.reference else: return NotImplemented FReferencedType = TypeVar('FReferencedType') class NullableReferenceFactory(RainbowFactory[NullableReference[FReferencedType]], Generic[FReferencedType]): def __init__(self, factory: RainbowFactory[FReferencedType]): assert isinstance(factory, RainbowFactory) self.factory = factory def from_bytes(self, source: bytes, resolver: HashResolver) -> NullableReference[FReferencedType]: assert isinstance(source, bytes) assert isinstance(resolver, HashResolver) if source == HashPoint.NULL_HASH: return NullableReference(Null(), self.factory) else: return NullableReference.of( ResolverOrigin(self.factory, source, resolver).hash_point() ) def loose(self) -> RainbowFactory[NullableReference[FReferencedType]]: return self