from typing import Callable, Optional, TypeVar, Generic

T = TypeVar("T")
U = TypeVar("U")

def expect(val: Optional[T], msg: str) -> T: ...
def do(val: Optional[T], fn: Callable[[T], U]) -> Optional[T]: ...
def map(val: Optional[T], fn: Callable[[T], U]) -> Optional[U]: ...
def map_or(val: Optional[T], fn: Callable[[T], U], default: U) -> U: ...
def map_or_else(
    val: Optional[T], fn: Callable[[T], U], factory: Callable[[], U]
) -> U: ...
def unwrap(val: Optional[T]) -> T: ...
def unwrap_or(val: Optional[T], default: T) -> T: ...
def unwrap_or_else(val: Optional[T], factory: Callable[[], T]) -> T: ...
def and_(val: Optional[T], other: Optional[U]) -> Optional[U]: ...
def and_then(
    val: Optional[T], fn: Callable[[T], Optional[U]]
) -> Optional[U]: ...
def or_(val: Optional[T], default: Optional[T]) -> Optional[T]: ...
def or_else(
    val: Optional[T], factory: Callable[[], Optional[T]]
) -> Optional[T]: ...
def contains(val: Optional[T], other: U) -> bool: ...
def filter(val: Optional[T], pred: Callable[[T], bool]) -> Optional[T]: ...
def xor(val: Optional[T], other: Optional[T]) -> Optional[T]: ...
def flatten(val: Optional[Optional[T]]) -> Optional[T]: ...

class Maybe(Generic[T]):
    val: Optional[T]
    def expect(self, msg: str) -> T: ...
    def do(self, fn: Callable[[T], U]) -> Optional[T]: ...
    def map(self, fn: Callable[[T], U]) -> Optional[U]: ...
    def map_or(self, fn: Callable[[T], U], default: U) -> U: ...
    def map_or_else(
        self, fn: Callable[[T], U], factory: Callable[[], U]
    ) -> U: ...
    def unwrap(self) -> T: ...
    def unwrap_or(self, default: T) -> T: ...
    def unwrap_or_else(self, fn: Callable[[], T]) -> T: ...
    def and_(self, other: Optional[U]) -> Optional[U]: ...
    def __and__(self, other: Optional[U]) -> Optional[U]: ...
    def and_then(self, fn: Callable[[T], Optional[U]]) -> Optional[U]: ...
    def or_(self, default: Optional[T]) -> Optional[T]: ...
    def __or__(self, default: Optional[T]) -> Optional[T]: ...
    def or_else(self, factory: Callable[[], Optional[T]]) -> Optional[T]: ...
    def contains(self, other: U) -> bool: ...
    def filter(self, pred: Callable[[T], bool]) -> Optional[T]: ...
    def xor(self, other: Optional[T]) -> Optional[T]: ...
    def __xor__(self, other: Optional[T]) -> Optional[T]: ...
    def flatten(self) -> Optional[T]: ...
    def __init__(self, val) -> None: ...
