sain.option API documentation

# sain.option

Rust's `Option<T>` type. A value that can either be `T` or `None`

View Source

      1# BSD 3-Clause License
      2#
      3# Copyright (c) 2022-Present, nxtlo
      4# All rights reserved.
      5#
      6# Redistribution and use in source and binary forms, with or without
      7# modification, are permitted provided that the following conditions are met:
      8#
      9# * Redistributions of source code must retain the above copyright notice, this
     10#   list of conditions and the following disclaimer.
     11#
     12# * Redistributions in binary form must reproduce the above copyright notice,
     13#   this list of conditions and the following disclaimer in the documentation
     14#   and/or other materials provided with the distribution.
     15#
     16# * Neither the name of the copyright holder nor the names of its
     17#   contributors may be used to endorse or promote products derived from
     18#   this software without specific prior written permission.
     19#
     20# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
     21# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     22# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     23# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
     24# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     25# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     26# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     27# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     28# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     29# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     30"""Rust's `Option<T>` type. A value that can either be `T` or `None`"""
     31
     32from __future__ import annotations
     33
     34__all__ = ("Some", "Option", "NOTHING")
     35
     36import typing
     37
     38from . import default as _default
     39from . import iter as _iter
     40from . import macros
     41from . import result as _result
     42from .macros import rustc_diagnostic_item
     43
     44T = typing.TypeVar("T")
     45T_co = typing.TypeVar("T_co", covariant=True)
     46
     47if typing.TYPE_CHECKING:
     48    import collections.abc as collections
     49
     50    U = typing.TypeVar("U")
     51    Fn = collections.Callable[[T], U]
     52    FnOnce = collections.Callable[[], U]
     53
     54
     55@rustc_diagnostic_item("Option")
     56@typing.final
     57class Some(typing.Generic[T], _default.Default["Option[T]"]):
     58    """The `Option` type represents optional value, higher-level abstraction over the `None` type.
     59
     60    It combines union of `T | None` in one convenient structure, allowing the users to manipulate and propagate
     61    the contained value idiomatically.
     62
     63    An `Option` value have multiple use cases:
     64
     65    * Initial values.
     66    * Return value for functions that may or may not contain a return value.
     67    * Optional parameters, class fields.
     68    * Swapping values.
     69
     70    Example
     71    -------
     72    ```py
     73    # the actual implementation of the object.
     74    from sain import Some
     75    # Here `Option` is used for type-hints only, you can include it under `TYPE_CHECKING` if you'd like.
     76    from sain import Option
     77
     78    def divide(numerator: float, denominator: float) -> Option[float]:
     79        if denominator == 0.0:
     80            return Some(None)
     81        return Some(numerator / denominator)
     82
     83    # Returns Option[float]
     84    result = divide(2.0, 3.0)
     85
     86    # Pattern match to retrieve the value
     87    match result:
     88        # The division is valid.
     89        case Some(x):
     90            print("Result:", x)
     91        # Invalid division, this is Some(None)
     92        case _:
     93            print("cannot divide by 0")
     94    ```
     95
     96    ### Converting `None`s into `RuntimeError`s
     97
     98    Sometimes we want to extract the value and cause an error to the caller if it doesn't exist,
     99
    100    because handling `Some/None` can be tedious, luckily we have several ways to deal with this.
    101
    102    ```py
    103    def ipaddr(s: str) -> Option[tuple[int, int, int, int]]:
    104        match s.split('.'):
    105            case [a, b, c, d]:
    106                return Some((int(a), int(b), int(c), int(d)))
    107            case _:
    108                return Some(None)
    109
    110    # calls `unwrap()` for you.
    111    ip = ~ipaddr("192.168.1.19")
    112    # causes a `RuntimeError` if it returns `None`.
    113    ip = ipaddr("192.168.1.19").unwrap()
    114    # causes a `RuntimeError` if it returns `None`, with a context message.
    115    ip = ipaddr("192.168.1.19").expect("i need an ip address :<")
    116    ```
    117
    118    The `~` operator will result in `tuple[int, int, int, int]` if the parsing succeed.
    119    unless the contained value is `None`, it will cause a `RuntimeError`.
    120
    121    If the value must be present, use `unwrap_or`, which takes a default parameter
    122    and returns it in-case `ipaddr` returns `None`
    123    ```py
    124    ip = ipaddr("blah blah blah").unwrap_or("192.168.1.255")
    125    # Results: 192.168.1.255
    126    ```
    127
    128    Overall, this type provides many other functional methods such as `map`, `filter`.
    129
    130    boolean checks such as `is_some`, `is_none`, converting between `Option` and `Result` using `ok_or`, and many more.
    131    """
    132
    133    __slots__ = ("_value",)
    134    __match_args__ = ("_value",)
    135
    136    def __init__(self, value: T | None, /) -> None:
    137        self._value = value
    138
    139    @staticmethod
    140    def default() -> Option[T]:
    141        """Default value for `Option<T>`. Returns `None` wrapped in `Some`.
    142
    143        Example
    144        -------
    145        ```py
    146        assert Some[int].default() is NOTHING
    147        ```
    148        """
    149        return NOTHING
    150
    151    # *- Reading the value -*
    152
    153    def transpose(self) -> T | None:
    154        """Convert `Option[T]` into `T | None`.
    155
    156        Examples
    157        --------
    158        ```py
    159        opt = Some('char')
    160        x = opt.transpose()
    161        assert x == 'char'
    162
    163        opt = Some(None)
    164        assert opt.transpose() is None
    165        ```
    166        """
    167        return self._value
    168
    169    def unwrap(self) -> T:
    170        """Unwrap the inner value either returning if its not `None` or raising a `RuntimeError`.
    171
    172        It's usually not recommended to use this method in production code, and instead use safer options such as `unwrap_or` or match patterns.
    173
    174        Example
    175        -------
    176        ```py
    177        value = Some(5)
    178        print(value.unwrap())
    179        # 5
    180
    181        value = Some(None)
    182        print(value.unwrap())
    183        # RuntimeError
    184        ```
    185
    186        Raises
    187        ------
    188        `RuntimeError`
    189            If the inner value is `None`.
    190        """
    191        if self._value is None:
    192            raise RuntimeError("Called `Option.unwrap()` on `None`.") from None
    193
    194        return self._value
    195
    196    def unwrap_or(self, default: T, /) -> T:
    197        """Unwrap the inner value either returning if its not `None` or returning `default`.
    198
    199        Example
    200        -------
    201        ```py
    202        value = Some(5)
    203        print(value.unwrap_or(10))
    204        # 5
    205
    206        # Type hint is required here.
    207        value: Option[int] = Some(None)
    208        print(value.unwrap_or(10))
    209        # 10
    210        ```
    211        """
    212        if self._value is None:
    213            return default
    214
    215        return self._value
    216
    217    def unwrap_or_else(self, f: FnOnce[T], /) -> T:
    218        """Unwrap the inner value either returning if its not `None` or calling `f` to get a default value.
    219
    220        Example
    221        -------
    222        ```py
    223        value = Some(5)
    224        print(value.unwrap_or_else(lambda: 10))
    225        # 5
    226
    227        value: Option[bool] = Some(None)
    228        print(value.unwrap_or_else(lambda: True))
    229        # True
    230        ```
    231        """
    232        if self._value is None:
    233            return f()
    234
    235        return self._value
    236
    237    @macros.unsafe
    238    def unwrap_unchecked(self) -> T:
    239        """Returns the contained Some value without checking that the value is not None.
    240
    241        Example
    242        -------
    243        ```py
    244        v: Option[float] = Some(1.2)
    245        v.unwrap_unchecked() # 1.2
    246
    247        v: Option[float] = Some(None)
    248        print(v.unwrap_unchecked()) # Undefined Behavior
    249        ```
    250        """
    251        #! SAFETY: The caller guarantees that the value is not None.
    252        return self._value  # pyright: ignore
    253
    254    def expect(self, message: str, /) -> T:
    255        """Returns the contained `Some` value.
    256
    257        raises if the value is `None` with a custom provided `message`.
    258
    259        Example
    260        -------
    261        ```py
    262        value = Some("Hello")
    263
    264        print(value.expect("Value is None"))
    265        # "Hello"
    266
    267        value: Option[str] = Some(None)
    268        print(value.expect("Value is None"))
    269        # RuntimeError("Value is None")
    270        ```
    271        """
    272        if self._value is None:
    273            raise RuntimeError(message)
    274
    275        return self._value
    276
    277    # *- object transformation -*
    278
    279    def map(self, f: Fn[T, U], /) -> Option[U]:
    280        """Map the inner value to another type. Returning `Some(None)` if `T` is `None`.
    281
    282        Example
    283        -------
    284        ```py
    285        value = Some(5.0)
    286
    287        print(value.map(lambda x: x * 2.0))
    288        # Some(10.0)
    289
    290        value: Option[bool] = Some(None)
    291        print(value)
    292        # Some(None)
    293        ```
    294        """
    295        if self._value is None:
    296            return NOTHING
    297
    298        return Some(f(self._value))
    299
    300    def map_or(self, default: U, f: Fn[T, U], /) -> U:
    301        """Map the inner value to another type or return `default` if its `None`.
    302
    303        Example
    304        -------
    305        ```py
    306        value: Option[float] = Some(5.0)
    307
    308        # map to int.
    309        print(value.map_or(0, int))
    310        # 6
    311
    312        value: Option[float] = Some(None)
    313        print(value.map_or(0, int)
    314        # 0
    315        ```
    316        """
    317        if self._value is None:
    318            return default
    319
    320        return f(self._value)
    321
    322    def map_or_else(self, default: FnOnce[U], f: Fn[T, U], /) -> U:
    323        """Map the inner value to another type, or return `default()` if its `None`.
    324
    325        Example
    326        -------
    327        ```py
    328        def default() -> int:
    329            return sys.getsizeof(object())
    330
    331        value: Option[float] = Some(5.0)
    332
    333        # map to int.
    334        print(value.map_or_else(default, int))
    335        # 6
    336
    337        value: Option[float] = Some(None)
    338        print(value.map_or_else(default, int)
    339        # 28 <- size of object()
    340        ```
    341        """
    342        if self._value is None:
    343            return default()
    344
    345        return f(self._value)
    346
    347    def filter(self, predicate: Fn[T, bool]) -> Option[T]:
    348        """Returns `Some(None)` if the contained value is `None`,
    349
    350        otherwise calls the predicate and returns `Some(T)` if the predicate returns `True`.
    351
    352        Example
    353        -------
    354        ```py
    355        value = Some([1, 2, 3])
    356
    357        print(value.filter(lambda x: 1 in x))
    358        # Some([1, 2, 3])
    359
    360        value: Option[int] = Some([1, 2, 3]) # or Some(None)
    361        print(value.filter(lambda x: 1 not in x))
    362        # None
    363        ```
    364        """
    365        if (value := self._value) is not None:
    366            if predicate(value):
    367                return Some(value)
    368
    369        return NOTHING
    370
    371    def ok_or(self, err: U) -> _result.Result[T, U]:
    372        """Transforms the `Option<T>` into a `Result<T, E>`, mapping `Some(v)` to `Ok(v)` and `None` to `Err(err)`.
    373
    374        Example
    375        -------
    376        ```py
    377        xyz: Option[str] = Some("foo")
    378        assert xyz.ok_or(None) == Ok("foo")
    379
    380        xyz: Option[str] = Some(None)
    381        assert xyz.ok_or(None) == Err(None)
    382        ```
    383        """
    384        if self._value is None:
    385            return _result.Err(err)
    386
    387        return _result.Ok(self._value)
    388
    389    def ok_or_else(self, err: FnOnce[U]) -> _result.Result[T, U]:
    390        """Transforms the `Option<T>` into a `Result<T, E>`, mapping `Some(v)` to `Ok(v)` and `None` to `Err(err())`.
    391
    392        Example
    393        -------
    394        ```py
    395        xyz: Option[str] = Some("foo")
    396        assert xyz.ok_or(None) == Ok("foo")
    397
    398        xyz: Option[str] = Some(None)
    399        assert xyz.ok_or(None) == Err(None)
    400        ```
    401        """
    402        if self._value is None:
    403            return _result.Err(err())
    404
    405        return _result.Ok(self._value)
    406
    407    def zip(self, other: Option[U]) -> Option[tuple[T, U]]:
    408        """Zips `self` with `other`.
    409
    410        if `self` is `Some(s)` and other is `Some(o)`, this returns `Some((s, o))` otherwise `None`.
    411
    412        Example
    413        -------
    414        ```py
    415        x = Some(1)
    416        y = Some("hi")
    417        z: Option[str] = Some(None)
    418
    419        assert x.zip(y) == Some((1, "hi"))
    420        assert x.zip(z) == Some(None)
    421        ```
    422        """
    423        if self._value is not None and other._value is not None:
    424            return Some((self._value, other._value))
    425
    426        return NOTHING
    427
    428    def zip_with(
    429        self, other: Option[U], f: collections.Callable[[T, U], T_co]
    430    ) -> Option[T_co]:
    431        """Zips `self` with `other` using function `f`.
    432
    433        if `self` is `Some(s)` and other is `Some(o)`, this returns `Some(f(s, o))` otherwise `None`.
    434
    435        Example
    436        -------
    437        ```py
    438        @dataclass
    439        class Point:
    440            x: float
    441            y: float
    442
    443        x, y = Some(32.1), Some(42.4)
    444        assert x.zip_with(y, Point) == Some(Point(32.1, 42.4))
    445        ```
    446        """
    447        if self._value is not None and other._value is not None:
    448            return Some(f(self._value, other._value))
    449
    450        return NOTHING
    451
    452    # *- Inner operations *-
    453
    454    def take(self) -> Option[T]:
    455        """Take the value from `self` Setting it to `None`, and then return `Some(v)`.
    456
    457        If you don't care about the original value, use `Option.clear()` instead.
    458
    459        Example
    460        -------
    461        ```py
    462        original = Some("Hi")
    463        new = original.take()
    464
    465        print(original, new)
    466        # None, Some("Hi")
    467        ```
    468        """
    469        if self._value is None:
    470            return NOTHING
    471
    472        val = self._value
    473        self._value = None
    474        return Some(val)
    475
    476    def take_if(self, predicate: collections.Callable[[T], bool]) -> Option[T]:
    477        """Take the value from `Self`, Setting it to `None` only if predicate returns `True`.
    478
    479        If you don't care about the original value, use `Option.clear_if()` instead.
    480
    481        Example
    482        -------
    483        ```py
    484        def validate(email: str) -> bool:
    485            # you can obviously validate this better.
    486            return email.find('@') == 1
    487
    488        original = Some("flex@gg.com")
    489        valid = original.take_if(validate)
    490        assert is_allowed.is_some() and original.is_none()
    491
    492        original = Some("mail.example.com")
    493        invalid = original.take_if(validate)
    494        assert invalid.is_none() and original.is_some()
    495        ```
    496        """
    497        if self.map_or(False, predicate):
    498            return self.take()
    499
    500        return NOTHING
    501
    502    def clear(self) -> None:
    503        """Clear the inner value, setting it to `None`.
    504
    505        If you care about the original value, use `Option.take()` instead.
    506
    507        Example
    508        -------
    509        ```py
    510        value = Some("Hello")
    511        value.clear()
    512        assert value.is_none()
    513        ```
    514        """
    515        self._value = None
    516
    517    def clear_if(self, predicate: Fn[T, bool]) -> None:
    518        """Clear the inner value, setting it to `None` if the predicate returns `True`.
    519
    520        If you care about the original value, use `Option.take_if()` instead.
    521
    522        Example
    523        -------
    524        ```py
    525        value = Some("Hello")
    526        value.clear_if(lambda x: x == "Hello")
    527        assert value.is_none()
    528        ```
    529        """
    530        if self._value is not None and predicate(self._value):
    531            self._value = None
    532
    533    def replace(self, value: T) -> Option[T]:
    534        """Replace the contained value with another value.
    535
    536        Use `Option.insert` if you want to return the original value
    537        that got inserted instead of `self`
    538
    539        Example
    540        -------
    541        ```py
    542        value: Option[str] = Some(None)
    543        value.replace("Hello")
    544        # Some("Hello")
    545        ```
    546        """
    547        self._value = value
    548        return self
    549
    550    def insert(self, value: T) -> T:
    551        """Insert a value into the option, and then return a reference to it.
    552
    553        This will overwrite the old value if it was already contained.
    554
    555        Example
    556        -------
    557        ```py
    558        flag: Option[bool] = Some(None)
    559        flag_ref = flag.insert(True)
    560        assert flag_ref == True
    561        assert flag.unwrap() == True
    562        ```
    563        """
    564        self._value = value
    565        return value
    566
    567    def get_or_insert(self, value: T) -> T:
    568        """Insert a value into the option if it was `None`,
    569        and then return a reference to it.
    570
    571        Example
    572        -------
    573        ```py
    574        state: Option[bool] = Some(None)
    575        assert state.get_or_insert(True) is True
    576        assert state.get_or_insert(False) is True
    577        ```
    578        """
    579        if self._value is not None:
    580            return self._value
    581
    582        self._value = value
    583        return value
    584
    585    def get_or_insert_with(self, f: FnOnce[T]) -> T:
    586        """Insert a value into the option computed from `f()` if it was `None`,
    587        and then return a reference to it.
    588
    589        Example
    590        -------
    591        ```py
    592        flag: Option[bool] = Some(None)
    593        flag_ref = flag.insert(True)
    594        assert flag_ref == True
    595        assert flag.unwrap() == True
    596        ```
    597        """
    598        if self._value is not None:
    599            return self._value
    600
    601        v = self._value = f()
    602        return v
    603
    604    def and_ok(self, optb: Option[T]) -> Option[T]:
    605        """Returns `None` if `self` or `optb` is `None`, otherwise return `optb`.
    606
    607        aliases: `Option::and`
    608
    609        Example
    610        -------
    611        ```py
    612        x = Some(1)
    613        y: Option[str] = Some(None)
    614        assert x.and_ok(y) == Some(None)
    615
    616        x: Option[str] = Some(None)
    617        y = Some(1)
    618        assert x.and_ok(y) == Some(None)
    619
    620        x: Option[str] = Some("hi")
    621        y = Some(100)
    622        assert x.and_ok(y) == Some(100)
    623        ```
    624        """
    625        if self._value is None or optb._value is None:
    626            return optb
    627
    628        return NOTHING
    629
    630    def and_then(self, f: Fn[T, Option[T]]) -> Option[T]:
    631        """Returns `Some(None)` if the contained value is `None`, otherwise call `f()`
    632        on `T` and return `Option[T]`.
    633
    634        Example
    635        -------
    636        ```py
    637        value = Some(5)
    638        print(value.and_then(lambda x: Some(x * 2)))
    639        # Some(10)
    640
    641        value: Option[int] = Some(None)
    642        print(value.and_then(lambda x: Some(x * 2)))
    643        # Some(None)
    644        ```
    645        """
    646        if self._value is None:
    647            return NOTHING
    648
    649        return f(self._value)
    650
    651    def inspect(self, f: Fn[T, typing.Any]) -> Option[T]:
    652        """Calls `f()` on the contained value if it was `Some(v)`, otherwise does nothing.
    653
    654        Example
    655        -------
    656        ```py
    657        def debug(x: str) -> None:
    658            print("Debugging:", x)
    659
    660        value = Some("foo")
    661        inner = value.inspect(debug).expect("no value to debug")
    662        # prints: Debugging: "foo"
    663
    664        value: Option[str] = Some(None)
    665        value.inspect(debug) # prints nothing
    666        """
    667        if self._value is not None:
    668            f(self._value)
    669
    670        return self
    671
    672    # *- Builder methods *-
    673
    674    def iter(self) -> _iter.ExactSizeIterator[T]:
    675        """Returns an iterator over the contained value.
    676
    677        Example
    678        -------
    679        ```py
    680        from sain import Some
    681        value = Some("gg").iter()
    682        assert value.next() == Some("gg")
    683
    684        value: Option[int] = Some(None)
    685        assert value.iter().next().is_none()
    686        ```
    687        """
    688        if self._value is None:
    689            return _iter.empty()
    690
    691        return _iter.once(self._value)
    692
    693    # *- Boolean checks *-
    694
    695    def is_some(self) -> bool:
    696        """Returns `True` if the contained value is not `None`, otherwise returns `False`.
    697
    698        Example
    699        -------
    700        ```py
    701        value = Some(5)
    702        print(value.is_some())
    703        # True
    704
    705        value: Option[int] = Some(None)
    706        print(value.is_some())
    707        # False
    708        ```
    709        """
    710        return self._value is not None
    711
    712    def is_some_and(self, predicate: Fn[T, bool]) -> bool:
    713        """Returns `True` if the contained value is not `None` and
    714        the predicate returns `True`, otherwise returns `False`.
    715
    716        Example
    717        -------
    718        ```py
    719        value = Some(5)
    720        print(value.is_some_and(lambda x: x > 3))
    721        # True
    722
    723        value: Option[int] = Some(None)
    724        print(value.is_some_and(lambda x: x > 3))
    725        # False
    726        ```
    727        """
    728        return self._value is not None and predicate(self._value)
    729
    730    def is_none(self) -> bool:
    731        """Returns `True` if the contained value is `None`, otherwise returns `False`.
    732
    733        Example
    734        -------
    735        ```py
    736        value = Some(5)
    737        print(value.is_none())
    738        # False
    739
    740        value: Option[int] = Some(None)
    741        print(value.is_none())
    742        # True
    743        ```
    744        """
    745        return self._value is None
    746
    747    def is_none_or(self, f: Fn[T, bool]) -> bool:
    748        """Returns `True` if the contained value is `None` or the predicate returns `True`,
    749        otherwise returns `False`.
    750
    751        Example
    752        -------
    753        ```py
    754        value = Some(5)
    755        print(value.is_none_or(lambda x: x > 3))
    756        # False
    757
    758        value: Option[int] = Some(None)
    759        print(value.is_none_or(lambda x: x > 3))
    760        # True
    761        ```
    762        """
    763        match self._value:
    764            case None:
    765                return True
    766            case x:
    767                return f(x)
    768
    769    def __repr__(self) -> str:
    770        if self._value is None:
    771            return "None"
    772        return f"Some({self._value!r})"
    773
    774    __str__ = __repr__
    775
    776    def __invert__(self) -> T:
    777        return self.unwrap()
    778
    779    def __or__(self, other: T) -> T:
    780        return self._value if self._value is not None else other
    781
    782    def __bool__(self) -> bool:
    783        return self._value is not None
    784
    785    def __eq__(self, other: None | object) -> bool:
    786        if other is None:
    787            return self._value is None
    788
    789        if not isinstance(other, Some):
    790            return NotImplemented
    791
    792        return self._value == other._value  # pyright: ignore[reportUnknownVariableType, reportUnknownMemberType]
    793
    794    def __ne__(self, other: object) -> bool:
    795        return not self.__eq__(other)
    796
    797    def __hash__(self) -> int:
    798        return hash(self._value)
    799
    800
    801Option: typing.TypeAlias = "Some[T]"
    802"""A type hint for a value that can be `Some<T>` or `None`.
    803
    804The reason this exist is to satisfy the UX with Rust's type system.
    805
    806Example
    807-------
    808```py
    809from __future__ import annotations
    810
    811import typing
    812from sain import Some
    813
    814if typing.CHECKING:
    815    from sain import Option
    816
    817foo: Option[str] = Some(None)
    818```
    819"""
    820
    821# FIXME: I just realized how unsafe this is since it can be mutated and potentially cause catastrophic bugs.
    822# maybe better to just use nothing_unchecked() instead or `Some(None)`.
    823NOTHING: typing.Final[Some[typing.Any]] = Some(None)
    824"""A constant that is always `Some(None)`.
    825
    826Example
    827-------
    828```py
    829from sain import NOTHING, Some
    830
    831place_holder: Option[str] = NOTHING
    832assert NOTHING == Some(None) # True
    833```
    834"""
    835
    836
    837@typing.no_type_check
    838@macros.unsafe
    839def nothing_unchecked() -> Option[T]:
    840    """A placeholder that always returns `sain.NOTHING` but acts like it returns `Option[T]`.
    841
    842    This is useful to avoid constructing new `Some(None)` and want to return `T` in the future.
    843
    844    Example
    845    -------
    846    ```py
    847    class User:
    848        username: str
    849
    850        def name(self) -> Option[str]:
    851            if '@' not in self.username:
    852                # even though the type of `NOTHING` is `Option[None]`.
    853                # we trick the type checker into thinking
    854                # that its an `Option[str]`.
    855                return NOTHING
    856
    857            return Some(self.username.split('@')[0])
    858    ```
    859    """
    860    return typing.cast("Option[T]", NOTHING)

@rustc_diagnostic_item('Option')
@typing.final
class Some(typing.Generic[~T], sain.default.Default[ForwardRef('Option[T]')]): View Source

     56@rustc_diagnostic_item("Option")
     57@typing.final
     58class Some(typing.Generic[T], _default.Default["Option[T]"]):
     59    """The `Option` type represents optional value, higher-level abstraction over the `None` type.
     60
     61    It combines union of `T | None` in one convenient structure, allowing the users to manipulate and propagate
     62    the contained value idiomatically.
     63
     64    An `Option` value have multiple use cases:
     65
     66    * Initial values.
     67    * Return value for functions that may or may not contain a return value.
     68    * Optional parameters, class fields.
     69    * Swapping values.
     70
     71    Example
     72    -------
     73    ```py
     74    # the actual implementation of the object.
     75    from sain import Some
     76    # Here `Option` is used for type-hints only, you can include it under `TYPE_CHECKING` if you'd like.
     77    from sain import Option
     78
     79    def divide(numerator: float, denominator: float) -> Option[float]:
     80        if denominator == 0.0:
     81            return Some(None)
     82        return Some(numerator / denominator)
     83
     84    # Returns Option[float]
     85    result = divide(2.0, 3.0)
     86
     87    # Pattern match to retrieve the value
     88    match result:
     89        # The division is valid.
     90        case Some(x):
     91            print("Result:", x)
     92        # Invalid division, this is Some(None)
     93        case _:
     94            print("cannot divide by 0")
     95    ```
     96
     97    ### Converting `None`s into `RuntimeError`s
     98
     99    Sometimes we want to extract the value and cause an error to the caller if it doesn't exist,
    100
    101    because handling `Some/None` can be tedious, luckily we have several ways to deal with this.
    102
    103    ```py
    104    def ipaddr(s: str) -> Option[tuple[int, int, int, int]]:
    105        match s.split('.'):
    106            case [a, b, c, d]:
    107                return Some((int(a), int(b), int(c), int(d)))
    108            case _:
    109                return Some(None)
    110
    111    # calls `unwrap()` for you.
    112    ip = ~ipaddr("192.168.1.19")
    113    # causes a `RuntimeError` if it returns `None`.
    114    ip = ipaddr("192.168.1.19").unwrap()
    115    # causes a `RuntimeError` if it returns `None`, with a context message.
    116    ip = ipaddr("192.168.1.19").expect("i need an ip address :<")
    117    ```
    118
    119    The `~` operator will result in `tuple[int, int, int, int]` if the parsing succeed.
    120    unless the contained value is `None`, it will cause a `RuntimeError`.
    121
    122    If the value must be present, use `unwrap_or`, which takes a default parameter
    123    and returns it in-case `ipaddr` returns `None`
    124    ```py
    125    ip = ipaddr("blah blah blah").unwrap_or("192.168.1.255")
    126    # Results: 192.168.1.255
    127    ```
    128
    129    Overall, this type provides many other functional methods such as `map`, `filter`.
    130
    131    boolean checks such as `is_some`, `is_none`, converting between `Option` and `Result` using `ok_or`, and many more.
    132    """
    133
    134    __slots__ = ("_value",)
    135    __match_args__ = ("_value",)
    136
    137    def __init__(self, value: T | None, /) -> None:
    138        self._value = value
    139
    140    @staticmethod
    141    def default() -> Option[T]:
    142        """Default value for `Option<T>`. Returns `None` wrapped in `Some`.
    143
    144        Example
    145        -------
    146        ```py
    147        assert Some[int].default() is NOTHING
    148        ```
    149        """
    150        return NOTHING
    151
    152    # *- Reading the value -*
    153
    154    def transpose(self) -> T | None:
    155        """Convert `Option[T]` into `T | None`.
    156
    157        Examples
    158        --------
    159        ```py
    160        opt = Some('char')
    161        x = opt.transpose()
    162        assert x == 'char'
    163
    164        opt = Some(None)
    165        assert opt.transpose() is None
    166        ```
    167        """
    168        return self._value
    169
    170    def unwrap(self) -> T:
    171        """Unwrap the inner value either returning if its not `None` or raising a `RuntimeError`.
    172
    173        It's usually not recommended to use this method in production code, and instead use safer options such as `unwrap_or` or match patterns.
    174
    175        Example
    176        -------
    177        ```py
    178        value = Some(5)
    179        print(value.unwrap())
    180        # 5
    181
    182        value = Some(None)
    183        print(value.unwrap())
    184        # RuntimeError
    185        ```
    186
    187        Raises
    188        ------
    189        `RuntimeError`
    190            If the inner value is `None`.
    191        """
    192        if self._value is None:
    193            raise RuntimeError("Called `Option.unwrap()` on `None`.") from None
    194
    195        return self._value
    196
    197    def unwrap_or(self, default: T, /) -> T:
    198        """Unwrap the inner value either returning if its not `None` or returning `default`.
    199
    200        Example
    201        -------
    202        ```py
    203        value = Some(5)
    204        print(value.unwrap_or(10))
    205        # 5
    206
    207        # Type hint is required here.
    208        value: Option[int] = Some(None)
    209        print(value.unwrap_or(10))
    210        # 10
    211        ```
    212        """
    213        if self._value is None:
    214            return default
    215
    216        return self._value
    217
    218    def unwrap_or_else(self, f: FnOnce[T], /) -> T:
    219        """Unwrap the inner value either returning if its not `None` or calling `f` to get a default value.
    220
    221        Example
    222        -------
    223        ```py
    224        value = Some(5)
    225        print(value.unwrap_or_else(lambda: 10))
    226        # 5
    227
    228        value: Option[bool] = Some(None)
    229        print(value.unwrap_or_else(lambda: True))
    230        # True
    231        ```
    232        """
    233        if self._value is None:
    234            return f()
    235
    236        return self._value
    237
    238    @macros.unsafe
    239    def unwrap_unchecked(self) -> T:
    240        """Returns the contained Some value without checking that the value is not None.
    241
    242        Example
    243        -------
    244        ```py
    245        v: Option[float] = Some(1.2)
    246        v.unwrap_unchecked() # 1.2
    247
    248        v: Option[float] = Some(None)
    249        print(v.unwrap_unchecked()) # Undefined Behavior
    250        ```
    251        """
    252        #! SAFETY: The caller guarantees that the value is not None.
    253        return self._value  # pyright: ignore
    254
    255    def expect(self, message: str, /) -> T:
    256        """Returns the contained `Some` value.
    257
    258        raises if the value is `None` with a custom provided `message`.
    259
    260        Example
    261        -------
    262        ```py
    263        value = Some("Hello")
    264
    265        print(value.expect("Value is None"))
    266        # "Hello"
    267
    268        value: Option[str] = Some(None)
    269        print(value.expect("Value is None"))
    270        # RuntimeError("Value is None")
    271        ```
    272        """
    273        if self._value is None:
    274            raise RuntimeError(message)
    275
    276        return self._value
    277
    278    # *- object transformation -*
    279
    280    def map(self, f: Fn[T, U], /) -> Option[U]:
    281        """Map the inner value to another type. Returning `Some(None)` if `T` is `None`.
    282
    283        Example
    284        -------
    285        ```py
    286        value = Some(5.0)
    287
    288        print(value.map(lambda x: x * 2.0))
    289        # Some(10.0)
    290
    291        value: Option[bool] = Some(None)
    292        print(value)
    293        # Some(None)
    294        ```
    295        """
    296        if self._value is None:
    297            return NOTHING
    298
    299        return Some(f(self._value))
    300
    301    def map_or(self, default: U, f: Fn[T, U], /) -> U:
    302        """Map the inner value to another type or return `default` if its `None`.
    303
    304        Example
    305        -------
    306        ```py
    307        value: Option[float] = Some(5.0)
    308
    309        # map to int.
    310        print(value.map_or(0, int))
    311        # 6
    312
    313        value: Option[float] = Some(None)
    314        print(value.map_or(0, int)
    315        # 0
    316        ```
    317        """
    318        if self._value is None:
    319            return default
    320
    321        return f(self._value)
    322
    323    def map_or_else(self, default: FnOnce[U], f: Fn[T, U], /) -> U:
    324        """Map the inner value to another type, or return `default()` if its `None`.
    325
    326        Example
    327        -------
    328        ```py
    329        def default() -> int:
    330            return sys.getsizeof(object())
    331
    332        value: Option[float] = Some(5.0)
    333
    334        # map to int.
    335        print(value.map_or_else(default, int))
    336        # 6
    337
    338        value: Option[float] = Some(None)
    339        print(value.map_or_else(default, int)
    340        # 28 <- size of object()
    341        ```
    342        """
    343        if self._value is None:
    344            return default()
    345
    346        return f(self._value)
    347
    348    def filter(self, predicate: Fn[T, bool]) -> Option[T]:
    349        """Returns `Some(None)` if the contained value is `None`,
    350
    351        otherwise calls the predicate and returns `Some(T)` if the predicate returns `True`.
    352
    353        Example
    354        -------
    355        ```py
    356        value = Some([1, 2, 3])
    357
    358        print(value.filter(lambda x: 1 in x))
    359        # Some([1, 2, 3])
    360
    361        value: Option[int] = Some([1, 2, 3]) # or Some(None)
    362        print(value.filter(lambda x: 1 not in x))
    363        # None
    364        ```
    365        """
    366        if (value := self._value) is not None:
    367            if predicate(value):
    368                return Some(value)
    369
    370        return NOTHING
    371
    372    def ok_or(self, err: U) -> _result.Result[T, U]:
    373        """Transforms the `Option<T>` into a `Result<T, E>`, mapping `Some(v)` to `Ok(v)` and `None` to `Err(err)`.
    374
    375        Example
    376        -------
    377        ```py
    378        xyz: Option[str] = Some("foo")
    379        assert xyz.ok_or(None) == Ok("foo")
    380
    381        xyz: Option[str] = Some(None)
    382        assert xyz.ok_or(None) == Err(None)
    383        ```
    384        """
    385        if self._value is None:
    386            return _result.Err(err)
    387
    388        return _result.Ok(self._value)
    389
    390    def ok_or_else(self, err: FnOnce[U]) -> _result.Result[T, U]:
    391        """Transforms the `Option<T>` into a `Result<T, E>`, mapping `Some(v)` to `Ok(v)` and `None` to `Err(err())`.
    392
    393        Example
    394        -------
    395        ```py
    396        xyz: Option[str] = Some("foo")
    397        assert xyz.ok_or(None) == Ok("foo")
    398
    399        xyz: Option[str] = Some(None)
    400        assert xyz.ok_or(None) == Err(None)
    401        ```
    402        """
    403        if self._value is None:
    404            return _result.Err(err())
    405
    406        return _result.Ok(self._value)
    407
    408    def zip(self, other: Option[U]) -> Option[tuple[T, U]]:
    409        """Zips `self` with `other`.
    410
    411        if `self` is `Some(s)` and other is `Some(o)`, this returns `Some((s, o))` otherwise `None`.
    412
    413        Example
    414        -------
    415        ```py
    416        x = Some(1)
    417        y = Some("hi")
    418        z: Option[str] = Some(None)
    419
    420        assert x.zip(y) == Some((1, "hi"))
    421        assert x.zip(z) == Some(None)
    422        ```
    423        """
    424        if self._value is not None and other._value is not None:
    425            return Some((self._value, other._value))
    426
    427        return NOTHING
    428
    429    def zip_with(
    430        self, other: Option[U], f: collections.Callable[[T, U], T_co]
    431    ) -> Option[T_co]:
    432        """Zips `self` with `other` using function `f`.
    433
    434        if `self` is `Some(s)` and other is `Some(o)`, this returns `Some(f(s, o))` otherwise `None`.
    435
    436        Example
    437        -------
    438        ```py
    439        @dataclass
    440        class Point:
    441            x: float
    442            y: float
    443
    444        x, y = Some(32.1), Some(42.4)
    445        assert x.zip_with(y, Point) == Some(Point(32.1, 42.4))
    446        ```
    447        """
    448        if self._value is not None and other._value is not None:
    449            return Some(f(self._value, other._value))
    450
    451        return NOTHING
    452
    453    # *- Inner operations *-
    454
    455    def take(self) -> Option[T]:
    456        """Take the value from `self` Setting it to `None`, and then return `Some(v)`.
    457
    458        If you don't care about the original value, use `Option.clear()` instead.
    459
    460        Example
    461        -------
    462        ```py
    463        original = Some("Hi")
    464        new = original.take()
    465
    466        print(original, new)
    467        # None, Some("Hi")
    468        ```
    469        """
    470        if self._value is None:
    471            return NOTHING
    472
    473        val = self._value
    474        self._value = None
    475        return Some(val)
    476
    477    def take_if(self, predicate: collections.Callable[[T], bool]) -> Option[T]:
    478        """Take the value from `Self`, Setting it to `None` only if predicate returns `True`.
    479
    480        If you don't care about the original value, use `Option.clear_if()` instead.
    481
    482        Example
    483        -------
    484        ```py
    485        def validate(email: str) -> bool:
    486            # you can obviously validate this better.
    487            return email.find('@') == 1
    488
    489        original = Some("flex@gg.com")
    490        valid = original.take_if(validate)
    491        assert is_allowed.is_some() and original.is_none()
    492
    493        original = Some("mail.example.com")
    494        invalid = original.take_if(validate)
    495        assert invalid.is_none() and original.is_some()
    496        ```
    497        """
    498        if self.map_or(False, predicate):
    499            return self.take()
    500
    501        return NOTHING
    502
    503    def clear(self) -> None:
    504        """Clear the inner value, setting it to `None`.
    505
    506        If you care about the original value, use `Option.take()` instead.
    507
    508        Example
    509        -------
    510        ```py
    511        value = Some("Hello")
    512        value.clear()
    513        assert value.is_none()
    514        ```
    515        """
    516        self._value = None
    517
    518    def clear_if(self, predicate: Fn[T, bool]) -> None:
    519        """Clear the inner value, setting it to `None` if the predicate returns `True`.
    520
    521        If you care about the original value, use `Option.take_if()` instead.
    522
    523        Example
    524        -------
    525        ```py
    526        value = Some("Hello")
    527        value.clear_if(lambda x: x == "Hello")
    528        assert value.is_none()
    529        ```
    530        """
    531        if self._value is not None and predicate(self._value):
    532            self._value = None
    533
    534    def replace(self, value: T) -> Option[T]:
    535        """Replace the contained value with another value.
    536
    537        Use `Option.insert` if you want to return the original value
    538        that got inserted instead of `self`
    539
    540        Example
    541        -------
    542        ```py
    543        value: Option[str] = Some(None)
    544        value.replace("Hello")
    545        # Some("Hello")
    546        ```
    547        """
    548        self._value = value
    549        return self
    550
    551    def insert(self, value: T) -> T:
    552        """Insert a value into the option, and then return a reference to it.
    553
    554        This will overwrite the old value if it was already contained.
    555
    556        Example
    557        -------
    558        ```py
    559        flag: Option[bool] = Some(None)
    560        flag_ref = flag.insert(True)
    561        assert flag_ref == True
    562        assert flag.unwrap() == True
    563        ```
    564        """
    565        self._value = value
    566        return value
    567
    568    def get_or_insert(self, value: T) -> T:
    569        """Insert a value into the option if it was `None`,
    570        and then return a reference to it.
    571
    572        Example
    573        -------
    574        ```py
    575        state: Option[bool] = Some(None)
    576        assert state.get_or_insert(True) is True
    577        assert state.get_or_insert(False) is True
    578        ```
    579        """
    580        if self._value is not None:
    581            return self._value
    582
    583        self._value = value
    584        return value
    585
    586    def get_or_insert_with(self, f: FnOnce[T]) -> T:
    587        """Insert a value into the option computed from `f()` if it was `None`,
    588        and then return a reference to it.
    589
    590        Example
    591        -------
    592        ```py
    593        flag: Option[bool] = Some(None)
    594        flag_ref = flag.insert(True)
    595        assert flag_ref == True
    596        assert flag.unwrap() == True
    597        ```
    598        """
    599        if self._value is not None:
    600            return self._value
    601
    602        v = self._value = f()
    603        return v
    604
    605    def and_ok(self, optb: Option[T]) -> Option[T]:
    606        """Returns `None` if `self` or `optb` is `None`, otherwise return `optb`.
    607
    608        aliases: `Option::and`
    609
    610        Example
    611        -------
    612        ```py
    613        x = Some(1)
    614        y: Option[str] = Some(None)
    615        assert x.and_ok(y) == Some(None)
    616
    617        x: Option[str] = Some(None)
    618        y = Some(1)
    619        assert x.and_ok(y) == Some(None)
    620
    621        x: Option[str] = Some("hi")
    622        y = Some(100)
    623        assert x.and_ok(y) == Some(100)
    624        ```
    625        """
    626        if self._value is None or optb._value is None:
    627            return optb
    628
    629        return NOTHING
    630
    631    def and_then(self, f: Fn[T, Option[T]]) -> Option[T]:
    632        """Returns `Some(None)` if the contained value is `None`, otherwise call `f()`
    633        on `T` and return `Option[T]`.
    634
    635        Example
    636        -------
    637        ```py
    638        value = Some(5)
    639        print(value.and_then(lambda x: Some(x * 2)))
    640        # Some(10)
    641
    642        value: Option[int] = Some(None)
    643        print(value.and_then(lambda x: Some(x * 2)))
    644        # Some(None)
    645        ```
    646        """
    647        if self._value is None:
    648            return NOTHING
    649
    650        return f(self._value)
    651
    652    def inspect(self, f: Fn[T, typing.Any]) -> Option[T]:
    653        """Calls `f()` on the contained value if it was `Some(v)`, otherwise does nothing.
    654
    655        Example
    656        -------
    657        ```py
    658        def debug(x: str) -> None:
    659            print("Debugging:", x)
    660
    661        value = Some("foo")
    662        inner = value.inspect(debug).expect("no value to debug")
    663        # prints: Debugging: "foo"
    664
    665        value: Option[str] = Some(None)
    666        value.inspect(debug) # prints nothing
    667        """
    668        if self._value is not None:
    669            f(self._value)
    670
    671        return self
    672
    673    # *- Builder methods *-
    674
    675    def iter(self) -> _iter.ExactSizeIterator[T]:
    676        """Returns an iterator over the contained value.
    677
    678        Example
    679        -------
    680        ```py
    681        from sain import Some
    682        value = Some("gg").iter()
    683        assert value.next() == Some("gg")
    684
    685        value: Option[int] = Some(None)
    686        assert value.iter().next().is_none()
    687        ```
    688        """
    689        if self._value is None:
    690            return _iter.empty()
    691
    692        return _iter.once(self._value)
    693
    694    # *- Boolean checks *-
    695
    696    def is_some(self) -> bool:
    697        """Returns `True` if the contained value is not `None`, otherwise returns `False`.
    698
    699        Example
    700        -------
    701        ```py
    702        value = Some(5)
    703        print(value.is_some())
    704        # True
    705
    706        value: Option[int] = Some(None)
    707        print(value.is_some())
    708        # False
    709        ```
    710        """
    711        return self._value is not None
    712
    713    def is_some_and(self, predicate: Fn[T, bool]) -> bool:
    714        """Returns `True` if the contained value is not `None` and
    715        the predicate returns `True`, otherwise returns `False`.
    716
    717        Example
    718        -------
    719        ```py
    720        value = Some(5)
    721        print(value.is_some_and(lambda x: x > 3))
    722        # True
    723
    724        value: Option[int] = Some(None)
    725        print(value.is_some_and(lambda x: x > 3))
    726        # False
    727        ```
    728        """
    729        return self._value is not None and predicate(self._value)
    730
    731    def is_none(self) -> bool:
    732        """Returns `True` if the contained value is `None`, otherwise returns `False`.
    733
    734        Example
    735        -------
    736        ```py
    737        value = Some(5)
    738        print(value.is_none())
    739        # False
    740
    741        value: Option[int] = Some(None)
    742        print(value.is_none())
    743        # True
    744        ```
    745        """
    746        return self._value is None
    747
    748    def is_none_or(self, f: Fn[T, bool]) -> bool:
    749        """Returns `True` if the contained value is `None` or the predicate returns `True`,
    750        otherwise returns `False`.
    751
    752        Example
    753        -------
    754        ```py
    755        value = Some(5)
    756        print(value.is_none_or(lambda x: x > 3))
    757        # False
    758
    759        value: Option[int] = Some(None)
    760        print(value.is_none_or(lambda x: x > 3))
    761        # True
    762        ```
    763        """
    764        match self._value:
    765            case None:
    766                return True
    767            case x:
    768                return f(x)
    769
    770    def __repr__(self) -> str:
    771        if self._value is None:
    772            return "None"
    773        return f"Some({self._value!r})"
    774
    775    __str__ = __repr__
    776
    777    def __invert__(self) -> T:
    778        return self.unwrap()
    779
    780    def __or__(self, other: T) -> T:
    781        return self._value if self._value is not None else other
    782
    783    def __bool__(self) -> bool:
    784        return self._value is not None
    785
    786    def __eq__(self, other: None | object) -> bool:
    787        if other is None:
    788            return self._value is None
    789
    790        if not isinstance(other, Some):
    791            return NotImplemented
    792
    793        return self._value == other._value  # pyright: ignore[reportUnknownVariableType, reportUnknownMemberType]
    794
    795    def __ne__(self, other: object) -> bool:
    796        return not self.__eq__(other)
    797
    798    def __hash__(self) -> int:
    799        return hash(self._value)

An interface for an object that has a default value.

###### Example

    from sain import Default

    class Cache(Default[dict[str, Any]]):

        @staticmethod
        def default() -> dict[str, Any]:
            return {}

    cache = Cache.default()
    print(cache)
    assert isinstance(cache, Default)
    # {}

# Implementations

This class implements Default in Rust.

Some(value: 'T | None', /) View Source

    137    def __init__(self, value: T | None, /) -> None:
    138        self._value = value

@staticmethod
def default() -> 'Option[T]': View Source

    140    @staticmethod
    141    def default() -> Option[T]:
    142        """Default value for `Option<T>`. Returns `None` wrapped in `Some`.
    143
    144        Example
    145        -------
    146        ```py
    147        assert Some[int].default() is NOTHING
    148        ```
    149        """
    150        return NOTHING

Return the default value of the object.

def transpose(self) -> 'T | None': View Source

    154    def transpose(self) -> T | None:
    155        """Convert `Option[T]` into `T | None`.
    156
    157        Examples
    158        --------
    159        ```py
    160        opt = Some('char')
    161        x = opt.transpose()
    162        assert x == 'char'
    163
    164        opt = Some(None)
    165        assert opt.transpose() is None
    166        ```
    167        """
    168        return self._value

Convert `Option[T]` into `T | None`.

###### Examples

    opt = Some('char')
    x = opt.transpose()
    assert x == 'char'

    opt = Some(None)
    assert opt.transpose() is None

def unwrap(self, /) -> 'T': View Source

    170    def unwrap(self) -> T:
    171        """Unwrap the inner value either returning if its not `None` or raising a `RuntimeError`.
    172
    173        It's usually not recommended to use this method in production code, and instead use safer options such as `unwrap_or` or match patterns.
    174
    175        Example
    176        -------
    177        ```py
    178        value = Some(5)
    179        print(value.unwrap())
    180        # 5
    181
    182        value = Some(None)
    183        print(value.unwrap())
    184        # RuntimeError
    185        ```
    186
    187        Raises
    188        ------
    189        `RuntimeError`
    190            If the inner value is `None`.
    191        """
    192        if self._value is None:
    193            raise RuntimeError("Called `Option.unwrap()` on `None`.") from None
    194
    195        return self._value

Unwrap the inner value either returning if its not `None` or raising a `RuntimeError`.

It's usually not recommended to use this method in production code, and instead use safer options such as `unwrap_or` or match patterns.

###### Example

    value = Some(5)
    print(value.unwrap())
    # 5

    value = Some(None)
    print(value.unwrap())
    # RuntimeError

###### Raises

- `RuntimeError`: If the inner value is `None`.

def unwrap_or(self, default: 'T') -> 'T': View Source

    197    def unwrap_or(self, default: T, /) -> T:
    198        """Unwrap the inner value either returning if its not `None` or returning `default`.
    199
    200        Example
    201        -------
    202        ```py
    203        value = Some(5)
    204        print(value.unwrap_or(10))
    205        # 5
    206
    207        # Type hint is required here.
    208        value: Option[int] = Some(None)
    209        print(value.unwrap_or(10))
    210        # 10
    211        ```
    212        """
    213        if self._value is None:
    214            return default
    215
    216        return self._value

Unwrap the inner value either returning if its not `None` or returning `default`.

###### Example

    value = Some(5)
    print(value.unwrap_or(10))
    # 5

    # Type hint is required here.
    value: Option[int] = Some(None)
    print(value.unwrap_or(10))
    # 10

def unwrap_or_else(self, f: 'FnOnce[T]') -> 'T': View Source

    218    def unwrap_or_else(self, f: FnOnce[T], /) -> T:
    219        """Unwrap the inner value either returning if its not `None` or calling `f` to get a default value.
    220
    221        Example
    222        -------
    223        ```py
    224        value = Some(5)
    225        print(value.unwrap_or_else(lambda: 10))
    226        # 5
    227
    228        value: Option[bool] = Some(None)
    229        print(value.unwrap_or_else(lambda: True))
    230        # True
    231        ```
    232        """
    233        if self._value is None:
    234            return f()
    235
    236        return self._value

Unwrap the inner value either returning if its not `None` or calling `f` to get a default value.

###### Example

    value = Some(5)
    print(value.unwrap_or_else(lambda: 10))
    # 5

    value: Option[bool] = Some(None)
    print(value.unwrap_or_else(lambda: True))
    # True

@macros.unsafe
def unwrap_unchecked(self) -> 'T': View Source

    238    @macros.unsafe
    239    def unwrap_unchecked(self) -> T:
    240        """Returns the contained Some value without checking that the value is not None.
    241
    242        Example
    243        -------
    244        ```py
    245        v: Option[float] = Some(1.2)
    246        v.unwrap_unchecked() # 1.2
    247
    248        v: Option[float] = Some(None)
    249        print(v.unwrap_unchecked()) # Undefined Behavior
    250        ```
    251        """
    252        #! SAFETY: The caller guarantees that the value is not None.
    253        return self._value  # pyright: ignore

Returns the contained Some value without checking that the value is not None.

###### Example

    v: Option[float] = Some(1.2)
    v.unwrap_unchecked() # 1.2

    v: Option[float] = Some(None)
    print(v.unwrap_unchecked()) # Undefined Behavior

# Safety ⚠️

Calling this method without knowing the output is considered undefined behavior.

def expect(self, message: str) -> 'T': View Source

    255    def expect(self, message: str, /) -> T:
    256        """Returns the contained `Some` value.
    257
    258        raises if the value is `None` with a custom provided `message`.
    259
    260        Example
    261        -------
    262        ```py
    263        value = Some("Hello")
    264
    265        print(value.expect("Value is None"))
    266        # "Hello"
    267
    268        value: Option[str] = Some(None)
    269        print(value.expect("Value is None"))
    270        # RuntimeError("Value is None")
    271        ```
    272        """
    273        if self._value is None:
    274            raise RuntimeError(message)
    275
    276        return self._value

Returns the contained `Some` value.

raises if the value is `None` with a custom provided `message`.

###### Example

    value = Some("Hello")

    print(value.expect("Value is None"))
    # "Hello"

    value: Option[str] = Some(None)
    print(value.expect("Value is None"))
    # RuntimeError("Value is None")

def map(self, f: 'Fn[T, U]') -> 'Option[U]': View Source

    280    def map(self, f: Fn[T, U], /) -> Option[U]:
    281        """Map the inner value to another type. Returning `Some(None)` if `T` is `None`.
    282
    283        Example
    284        -------
    285        ```py
    286        value = Some(5.0)
    287
    288        print(value.map(lambda x: x * 2.0))
    289        # Some(10.0)
    290
    291        value: Option[bool] = Some(None)
    292        print(value)
    293        # Some(None)
    294        ```
    295        """
    296        if self._value is None:
    297            return NOTHING
    298
    299        return Some(f(self._value))

Map the inner value to another type. Returning `Some(None)` if `T` is `None`.

###### Example

    value = Some(5.0)

    print(value.map(lambda x: x * 2.0))
    # Some(10.0)

    value: Option[bool] = Some(None)
    print(value)
    # Some(None)

def map_or(self, default: 'U', f: 'Fn[T, U]') -> 'U': View Source

    301    def map_or(self, default: U, f: Fn[T, U], /) -> U:
    302        """Map the inner value to another type or return `default` if its `None`.
    303
    304        Example
    305        -------
    306        ```py
    307        value: Option[float] = Some(5.0)
    308
    309        # map to int.
    310        print(value.map_or(0, int))
    311        # 6
    312
    313        value: Option[float] = Some(None)
    314        print(value.map_or(0, int)
    315        # 0
    316        ```
    317        """
    318        if self._value is None:
    319            return default
    320
    321        return f(self._value)

Map the inner value to another type or return `default` if its `None`.

###### Example

    value: Option[float] = Some(5.0)

    # map to int.
    print(value.map_or(0, int))
    # 6

    value: Option[float] = Some(None)
    print(value.map_or(0, int)
    # 0

def map_or_else(self, default: 'FnOnce[U]', f: 'Fn[T, U]') -> 'U': View Source

    323    def map_or_else(self, default: FnOnce[U], f: Fn[T, U], /) -> U:
    324        """Map the inner value to another type, or return `default()` if its `None`.
    325
    326        Example
    327        -------
    328        ```py
    329        def default() -> int:
    330            return sys.getsizeof(object())
    331
    332        value: Option[float] = Some(5.0)
    333
    334        # map to int.
    335        print(value.map_or_else(default, int))
    336        # 6
    337
    338        value: Option[float] = Some(None)
    339        print(value.map_or_else(default, int)
    340        # 28 <- size of object()
    341        ```
    342        """
    343        if self._value is None:
    344            return default()
    345
    346        return f(self._value)

Map the inner value to another type, or return `default()` if its `None`.

###### Example

    def default() -> int:
        return sys.getsizeof(object())

    value: Option[float] = Some(5.0)

    # map to int.
    print(value.map_or_else(default, int))
    # 6

    value: Option[float] = Some(None)
    print(value.map_or_else(default, int)
    # 28 <- size of object()

def filter(self, predicate: 'Fn[T, bool]') -> 'Option[T]': View Source

    348    def filter(self, predicate: Fn[T, bool]) -> Option[T]:
    349        """Returns `Some(None)` if the contained value is `None`,
    350
    351        otherwise calls the predicate and returns `Some(T)` if the predicate returns `True`.
    352
    353        Example
    354        -------
    355        ```py
    356        value = Some([1, 2, 3])
    357
    358        print(value.filter(lambda x: 1 in x))
    359        # Some([1, 2, 3])
    360
    361        value: Option[int] = Some([1, 2, 3]) # or Some(None)
    362        print(value.filter(lambda x: 1 not in x))
    363        # None
    364        ```
    365        """
    366        if (value := self._value) is not None:
    367            if predicate(value):
    368                return Some(value)
    369
    370        return NOTHING

Returns `Some(None)` if the contained value is `None`,

otherwise calls the predicate and returns `Some(T)` if the predicate returns `True`.

###### Example

    value = Some([1, 2, 3])

    print(value.filter(lambda x: 1 in x))
    # Some([1, 2, 3])

    value: Option[int] = Some([1, 2, 3]) # or Some(None)
    print(value.filter(lambda x: 1 not in x))
    # None

def ok_or(self, err: 'E') -> 'Result[T, E]': View Source

    372    def ok_or(self, err: U) -> _result.Result[T, U]:
    373        """Transforms the `Option<T>` into a `Result<T, E>`, mapping `Some(v)` to `Ok(v)` and `None` to `Err(err)`.
    374
    375        Example
    376        -------
    377        ```py
    378        xyz: Option[str] = Some("foo")
    379        assert xyz.ok_or(None) == Ok("foo")
    380
    381        xyz: Option[str] = Some(None)
    382        assert xyz.ok_or(None) == Err(None)
    383        ```
    384        """
    385        if self._value is None:
    386            return _result.Err(err)
    387
    388        return _result.Ok(self._value)

Transforms the `Option<T>` into a `Result<T, E>`, mapping `Some(v)` to `Ok(v)` and `None` to `Err(err)`.

###### Example

    xyz: Option[str] = Some("foo")
    assert xyz.ok_or(None) == Ok("foo")

    xyz: Option[str] = Some(None)
    assert xyz.ok_or(None) == Err(None)

def ok_or_else(self, err: 'FnOnce[E]') -> 'Result[T, E]': View Source

    390    def ok_or_else(self, err: FnOnce[U]) -> _result.Result[T, U]:
    391        """Transforms the `Option<T>` into a `Result<T, E>`, mapping `Some(v)` to `Ok(v)` and `None` to `Err(err())`.
    392
    393        Example
    394        -------
    395        ```py
    396        xyz: Option[str] = Some("foo")
    397        assert xyz.ok_or(None) == Ok("foo")
    398
    399        xyz: Option[str] = Some(None)
    400        assert xyz.ok_or(None) == Err(None)
    401        ```
    402        """
    403        if self._value is None:
    404            return _result.Err(err())
    405
    406        return _result.Ok(self._value)

Transforms the `Option<T>` into a `Result<T, E>`, mapping `Some(v)` to `Ok(v)` and `None` to `Err(err())`.

###### Example

    xyz: Option[str] = Some("foo")
    assert xyz.ok_or(None) == Ok("foo")

    xyz: Option[str] = Some(None)
    assert xyz.ok_or(None) == Err(None)

def zip(self, other: 'Option[U]') -> 'Option[tuple[T, U]]': View Source

    408    def zip(self, other: Option[U]) -> Option[tuple[T, U]]:
    409        """Zips `self` with `other`.
    410
    411        if `self` is `Some(s)` and other is `Some(o)`, this returns `Some((s, o))` otherwise `None`.
    412
    413        Example
    414        -------
    415        ```py
    416        x = Some(1)
    417        y = Some("hi")
    418        z: Option[str] = Some(None)
    419
    420        assert x.zip(y) == Some((1, "hi"))
    421        assert x.zip(z) == Some(None)
    422        ```
    423        """
    424        if self._value is not None and other._value is not None:
    425            return Some((self._value, other._value))
    426
    427        return NOTHING

Zips `self` with `other`.

if `self` is `Some(s)` and other is `Some(o)`, this returns `Some((s, o))` otherwise `None`.

###### Example

    x = Some(1)
    y = Some("hi")
    z: Option[str] = Some(None)

    assert x.zip(y) == Some((1, "hi"))
    assert x.zip(z) == Some(None)

def zip_with( self, other: 'Option[U]', f: '_collections.Callable[[T, U], R]') -> 'Option[R]': View Source

    429    def zip_with(
    430        self, other: Option[U], f: collections.Callable[[T, U], T_co]
    431    ) -> Option[T_co]:
    432        """Zips `self` with `other` using function `f`.
    433
    434        if `self` is `Some(s)` and other is `Some(o)`, this returns `Some(f(s, o))` otherwise `None`.
    435
    436        Example
    437        -------
    438        ```py
    439        @dataclass
    440        class Point:
    441            x: float
    442            y: float
    443
    444        x, y = Some(32.1), Some(42.4)
    445        assert x.zip_with(y, Point) == Some(Point(32.1, 42.4))
    446        ```
    447        """
    448        if self._value is not None and other._value is not None:
    449            return Some(f(self._value, other._value))
    450
    451        return NOTHING

Zips `self` with `other` using function `f`.

if `self` is `Some(s)` and other is `Some(o)`, this returns `Some(f(s, o))` otherwise `None`.

###### Example

    @dataclass
    class Point:
        x: float
        y: float

    x, y = Some(32.1), Some(42.4)
    assert x.zip_with(y, Point) == Some(Point(32.1, 42.4))

def take(self) -> 'Option[T]': View Source

    455    def take(self) -> Option[T]:
    456        """Take the value from `self` Setting it to `None`, and then return `Some(v)`.
    457
    458        If you don't care about the original value, use `Option.clear()` instead.
    459
    460        Example
    461        -------
    462        ```py
    463        original = Some("Hi")
    464        new = original.take()
    465
    466        print(original, new)
    467        # None, Some("Hi")
    468        ```
    469        """
    470        if self._value is None:
    471            return NOTHING
    472
    473        val = self._value
    474        self._value = None
    475        return Some(val)

Take the value from `self` Setting it to `None`, and then return `Some(v)`.

If you don't care about the original value, use `Option.clear()` instead.

###### Example

    original = Some("Hi")
    new = original.take()

    print(original, new)
    # None, Some("Hi")

def take_if(self, predicate: 'Fn[T, bool]') -> 'Option[T]': View Source

    477    def take_if(self, predicate: collections.Callable[[T], bool]) -> Option[T]:
    478        """Take the value from `Self`, Setting it to `None` only if predicate returns `True`.
    479
    480        If you don't care about the original value, use `Option.clear_if()` instead.
    481
    482        Example
    483        -------
    484        ```py
    485        def validate(email: str) -> bool:
    486            # you can obviously validate this better.
    487            return email.find('@') == 1
    488
    489        original = Some("flex@gg.com")
    490        valid = original.take_if(validate)
    491        assert is_allowed.is_some() and original.is_none()
    492
    493        original = Some("mail.example.com")
    494        invalid = original.take_if(validate)
    495        assert invalid.is_none() and original.is_some()
    496        ```
    497        """
    498        if self.map_or(False, predicate):
    499            return self.take()
    500
    501        return NOTHING

Take the value from `Self`, Setting it to `None` only if predicate returns `True`.

If you don't care about the original value, use `Option.clear_if()` instead.

###### Example

    def validate(email: str) -> bool:
        # you can obviously validate this better.
        return email.find('@') == 1

    original = Some("flex@gg.com")
    valid = original.take_if(validate)
    assert is_allowed.is_some() and original.is_none()

    original = Some("mail.example.com")
    invalid = original.take_if(validate)
    assert invalid.is_none() and original.is_some()

def clear(self) -> None: View Source

    503    def clear(self) -> None:
    504        """Clear the inner value, setting it to `None`.
    505
    506        If you care about the original value, use `Option.take()` instead.
    507
    508        Example
    509        -------
    510        ```py
    511        value = Some("Hello")
    512        value.clear()
    513        assert value.is_none()
    514        ```
    515        """
    516        self._value = None

Clear the inner value, setting it to `None`.

If you care about the original value, use `Option.take()` instead.

###### Example

    value = Some("Hello")
    value.clear()
    assert value.is_none()

def clear_if(self, predicate: 'Fn[T, bool]') -> None: View Source

    518    def clear_if(self, predicate: Fn[T, bool]) -> None:
    519        """Clear the inner value, setting it to `None` if the predicate returns `True`.
    520
    521        If you care about the original value, use `Option.take_if()` instead.
    522
    523        Example
    524        -------
    525        ```py
    526        value = Some("Hello")
    527        value.clear_if(lambda x: x == "Hello")
    528        assert value.is_none()
    529        ```
    530        """
    531        if self._value is not None and predicate(self._value):
    532            self._value = None

Clear the inner value, setting it to `None` if the predicate returns `True`.

If you care about the original value, use `Option.take_if()` instead.

###### Example

    value = Some("Hello")
    value.clear_if(lambda x: x == "Hello")
    assert value.is_none()

def replace(self, value: 'T') -> 'Option[T]': View Source

    534    def replace(self, value: T) -> Option[T]:
    535        """Replace the contained value with another value.
    536
    537        Use `Option.insert` if you want to return the original value
    538        that got inserted instead of `self`
    539
    540        Example
    541        -------
    542        ```py
    543        value: Option[str] = Some(None)
    544        value.replace("Hello")
    545        # Some("Hello")
    546        ```
    547        """
    548        self._value = value
    549        return self

Replace the contained value with another value.

Use `Option.insert` if you want to return the original value that got inserted instead of `self`

###### Example

    value: Option[str] = Some(None)
    value.replace("Hello")
    # Some("Hello")

def insert(self, value: 'T') -> 'T': View Source

    551    def insert(self, value: T) -> T:
    552        """Insert a value into the option, and then return a reference to it.
    553
    554        This will overwrite the old value if it was already contained.
    555
    556        Example
    557        -------
    558        ```py
    559        flag: Option[bool] = Some(None)
    560        flag_ref = flag.insert(True)
    561        assert flag_ref == True
    562        assert flag.unwrap() == True
    563        ```
    564        """
    565        self._value = value
    566        return value

Insert a value into the option, and then return a reference to it.

This will overwrite the old value if it was already contained.

###### Example

    flag: Option[bool] = Some(None)
    flag_ref = flag.insert(True)
    assert flag_ref == True
    assert flag.unwrap() == True

def get_or_insert(self, value: 'T') -> 'T': View Source

    568    def get_or_insert(self, value: T) -> T:
    569        """Insert a value into the option if it was `None`,
    570        and then return a reference to it.
    571
    572        Example
    573        -------
    574        ```py
    575        state: Option[bool] = Some(None)
    576        assert state.get_or_insert(True) is True
    577        assert state.get_or_insert(False) is True
    578        ```
    579        """
    580        if self._value is not None:
    581            return self._value
    582
    583        self._value = value
    584        return value

Insert a value into the option if it was `None`, and then return a reference to it.

###### Example

    state: Option[bool] = Some(None)
    assert state.get_or_insert(True) is True
    assert state.get_or_insert(False) is True

def get_or_insert_with(self, f: 'FnOnce[T]') -> 'T': View Source

    586    def get_or_insert_with(self, f: FnOnce[T]) -> T:
    587        """Insert a value into the option computed from `f()` if it was `None`,
    588        and then return a reference to it.
    589
    590        Example
    591        -------
    592        ```py
    593        flag: Option[bool] = Some(None)
    594        flag_ref = flag.insert(True)
    595        assert flag_ref == True
    596        assert flag.unwrap() == True
    597        ```
    598        """
    599        if self._value is not None:
    600            return self._value
    601
    602        v = self._value = f()
    603        return v

Insert a value into the option computed from `f()` if it was `None`, and then return a reference to it.

###### Example

    flag: Option[bool] = Some(None)
    flag_ref = flag.insert(True)
    assert flag_ref == True
    assert flag.unwrap() == True

def and_ok(self, optb: 'Option[T]') -> 'Option[U]': View Source

    605    def and_ok(self, optb: Option[T]) -> Option[T]:
    606        """Returns `None` if `self` or `optb` is `None`, otherwise return `optb`.
    607
    608        aliases: `Option::and`
    609
    610        Example
    611        -------
    612        ```py
    613        x = Some(1)
    614        y: Option[str] = Some(None)
    615        assert x.and_ok(y) == Some(None)
    616
    617        x: Option[str] = Some(None)
    618        y = Some(1)
    619        assert x.and_ok(y) == Some(None)
    620
    621        x: Option[str] = Some("hi")
    622        y = Some(100)
    623        assert x.and_ok(y) == Some(100)
    624        ```
    625        """
    626        if self._value is None or optb._value is None:
    627            return optb
    628
    629        return NOTHING

Returns `None` if `self` or `optb` is `None`, otherwise return `optb`.

aliases: `Option::and`

###### Example

    x = Some(1)
    y: Option[str] = Some(None)
    assert x.and_ok(y) == Some(None)

    x: Option[str] = Some(None)
    y = Some(1)
    assert x.and_ok(y) == Some(None)

    x: Option[str] = Some("hi")
    y = Some(100)
    assert x.and_ok(y) == Some(100)

def and_then(self, f: 'Fn[T, Option[U]]') -> 'Option[U]': View Source

    631    def and_then(self, f: Fn[T, Option[T]]) -> Option[T]:
    632        """Returns `Some(None)` if the contained value is `None`, otherwise call `f()`
    633        on `T` and return `Option[T]`.
    634
    635        Example
    636        -------
    637        ```py
    638        value = Some(5)
    639        print(value.and_then(lambda x: Some(x * 2)))
    640        # Some(10)
    641
    642        value: Option[int] = Some(None)
    643        print(value.and_then(lambda x: Some(x * 2)))
    644        # Some(None)
    645        ```
    646        """
    647        if self._value is None:
    648            return NOTHING
    649
    650        return f(self._value)

Returns `Some(None)` if the contained value is `None`, otherwise call `f()` on `T` and return `Option[T]`.

###### Example

    value = Some(5)
    print(value.and_then(lambda x: Some(x * 2)))
    # Some(10)

    value: Option[int] = Some(None)
    print(value.and_then(lambda x: Some(x * 2)))
    # Some(None)

def inspect(self, f: 'Fn[T, _typing.Any]') -> 'Option[T]': View Source

    652    def inspect(self, f: Fn[T, typing.Any]) -> Option[T]:
    653        """Calls `f()` on the contained value if it was `Some(v)`, otherwise does nothing.
    654
    655        Example
    656        -------
    657        ```py
    658        def debug(x: str) -> None:
    659            print("Debugging:", x)
    660
    661        value = Some("foo")
    662        inner = value.inspect(debug).expect("no value to debug")
    663        # prints: Debugging: "foo"
    664
    665        value: Option[str] = Some(None)
    666        value.inspect(debug) # prints nothing
    667        """
    668        if self._value is not None:
    669            f(self._value)
    670
    671        return self

Calls `f()` on the contained value if it was `Some(v)`, otherwise does nothing.

###### Example

```py def debug(x: str) -> None: print("Debugging:", x)

value = Some("foo") inner = value.inspect(debug).expect("no value to debug")

# prints: Debugging: "foo"

value: Option[str] = Some(None) value.inspect(debug) # prints nothing

def iter(self) -> 'ExactSizeIterator[T]': View Source

    675    def iter(self) -> _iter.ExactSizeIterator[T]:
    676        """Returns an iterator over the contained value.
    677
    678        Example
    679        -------
    680        ```py
    681        from sain import Some
    682        value = Some("gg").iter()
    683        assert value.next() == Some("gg")
    684
    685        value: Option[int] = Some(None)
    686        assert value.iter().next().is_none()
    687        ```
    688        """
    689        if self._value is None:
    690            return _iter.empty()
    691
    692        return _iter.once(self._value)

Returns an iterator over the contained value.

###### Example

    from sain import Some
    value = Some("gg")sain.iter()
    assert value.next() == Some("gg")

    value: Option[int] = Some(None)
    assert value.iter().next().is_none()

def is_some(self) -> bool: View Source

    696    def is_some(self) -> bool:
    697        """Returns `True` if the contained value is not `None`, otherwise returns `False`.
    698
    699        Example
    700        -------
    701        ```py
    702        value = Some(5)
    703        print(value.is_some())
    704        # True
    705
    706        value: Option[int] = Some(None)
    707        print(value.is_some())
    708        # False
    709        ```
    710        """
    711        return self._value is not None

Returns `True` if the contained value is not `None`, otherwise returns `False`.

###### Example

    value = Some(5)
    print(value.is_some())
    # True

    value: Option[int] = Some(None)
    print(value.is_some())
    # False

def is_some_and(self, predicate: 'Fn[T, bool]') -> bool: View Source

    713    def is_some_and(self, predicate: Fn[T, bool]) -> bool:
    714        """Returns `True` if the contained value is not `None` and
    715        the predicate returns `True`, otherwise returns `False`.
    716
    717        Example
    718        -------
    719        ```py
    720        value = Some(5)
    721        print(value.is_some_and(lambda x: x > 3))
    722        # True
    723
    724        value: Option[int] = Some(None)
    725        print(value.is_some_and(lambda x: x > 3))
    726        # False
    727        ```
    728        """
    729        return self._value is not None and predicate(self._value)

Returns `True` if the contained value is not `None` and the predicate returns `True`, otherwise returns `False`.

###### Example

    value = Some(5)
    print(value.is_some_and(lambda x: x > 3))
    # True

    value: Option[int] = Some(None)
    print(value.is_some_and(lambda x: x > 3))
    # False

def is_none(self) -> bool: View Source

    731    def is_none(self) -> bool:
    732        """Returns `True` if the contained value is `None`, otherwise returns `False`.
    733
    734        Example
    735        -------
    736        ```py
    737        value = Some(5)
    738        print(value.is_none())
    739        # False
    740
    741        value: Option[int] = Some(None)
    742        print(value.is_none())
    743        # True
    744        ```
    745        """
    746        return self._value is None

Returns `True` if the contained value is `None`, otherwise returns `False`.

###### Example

    value = Some(5)
    print(value.is_none())
    # False

    value: Option[int] = Some(None)
    print(value.is_none())
    # True

def is_none_or(self, f: 'Fn[T, bool]') -> bool: View Source

    748    def is_none_or(self, f: Fn[T, bool]) -> bool:
    749        """Returns `True` if the contained value is `None` or the predicate returns `True`,
    750        otherwise returns `False`.
    751
    752        Example
    753        -------
    754        ```py
    755        value = Some(5)
    756        print(value.is_none_or(lambda x: x > 3))
    757        # False
    758
    759        value: Option[int] = Some(None)
    760        print(value.is_none_or(lambda x: x > 3))
    761        # True
    762        ```
    763        """
    764        match self._value:
    765            case None:
    766                return True
    767            case x:
    768                return f(x)

Returns `True` if the contained value is `None` or the predicate returns `True`, otherwise returns `False`.

###### Example

    value = Some(5)
    print(value.is_none_or(lambda x: x > 3))
    # False

    value: Option[int] = Some(None)
    print(value.is_none_or(lambda x: x > 3))
    # True

Option = 'Some[T]'

A type hint for a value that can be `Some<T>` or `None`.

The reason this exist is to satisfy the UX with Rust's type system.

###### Example

    from __future__ import annotations

    import typing
    from sain import Some

    if typing.CHECKING:
        from sain import Option

    foo: Option[str] = Some(None)

NOTHING: Option[typing.Any] = None

A constant that is always `Some(None)`.

###### Example

    from sain import NOTHING, Some

    place_holder: Option[str] = NOTHING
    assert NOTHING == Some(None) # True