sain.macros API documentation

# sain.macros

A module that contains useful functions and decorators for marking objects.

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
     31"""A module that contains useful functions and decorators for marking objects."""
     32
     33from __future__ import annotations
     34
     35__all__ = (
     36    "deprecated",
     37    "unimplemented",
     38    "todo",
     39    "doc",
     40    "assert_eq",
     41    "assert_ne",
     42    "include_str",
     43    "include_bytes",
     44    "safe",
     45    "unsafe",
     46    "rustc_diagnostic_item",
     47    "RustItem",
     48)
     49
     50import functools
     51import inspect
     52import sys
     53import typing
     54import warnings
     55
     56if typing.TYPE_CHECKING:
     57    from typing_extensions import LiteralString
     58
     59    T = typing.TypeVar("T", covariant=True)
     60    import collections.abc as collections
     61
     62    import _typeshed
     63
     64    P = typing.ParamSpec("P")
     65    U = typing.TypeVar("U")
     66    Read = _typeshed.FileDescriptorOrPath
     67    # fmt: off
     68    RustItem = typing.Literal[
     69        # mem
     70        "MaybeUninit",
     71        # option
     72        "Option", "Some", "None",
     73        # result
     74        "Result", "Ok", "Err",
     75        # macros
     76        "unimplemented", "todo",
     77        "deprecated", "doc",
     78        "cfg", "cfg_attr",
     79        "assert_eq", "assert_ne",
     80        "include_bytes", "include_str",
     81        # std::iter::*
     82        "Iterator", "Iter", "empty",
     83        "once", "repeat", "into_iter",
     84        # errors
     85        "Error", "catch_unwind",
     86        # sync
     87        "Lazy",
     88        "Once",
     89        # convert
     90        "From", "TryFrom",
     91        "Into", "TryInto",
     92        "convert_identity",
     93        # default
     94        "Default", "default_fn",
     95        # std::collections::*
     96        "HashMap",
     97        "Vec", "vec!",
     98        # alloc
     99        "String", "ToString",
    100        # keywords
    101        "unsafe",
    102        # primitives
    103        "&[u8]",
    104        "&mut [u8]",
    105        # time
    106        "Duration"
    107    ]
    108    """An array of all the Rust items that can be marked as `rustc_diagnostic_item`."""
    109    # fmt: on
    110
    111_MAP_TO_PATH: dict[RustItem, LiteralString] = {
    112    # mem
    113    "MaybeUninit": "std/mem/union.MaybeUninit.html",
    114    # option
    115    "Option": "std/option/enum.Option.html",
    116    "Some": "std/option/enum.Option.html#variant.Some",
    117    "None": "std/option/enum.Option.html#variant.None",
    118    # result,
    119    "Result": "std/result/enum.Result.html",
    120    "Ok": "std/result/enum.Result.html#variant.Ok",
    121    "Err": "std/result/enum.Result.html#variant.Err",
    122    # macros
    123    "unimplemented": "std/macro.unimplemented.html",
    124    "todo": "std/macro.todo.html",
    125    "deprecated": "reference/attributes/diagnostics.html#the-deprecated-attribute",
    126    "cfg": "std/macro.cfg.html",
    127    "cfg_attr": "reference/conditional-compilation.html#the-cfg_attr-attribute",
    128    "doc": "rustdoc/write-documentation/the-doc-attribute.html",
    129    "assert_eq": "std/macro.assert_eq.html",
    130    "assert_ne": "std/macro.assert_ne.html",
    131    "include_bytes": "std/macro.include_bytes.html",
    132    "include_str": "std/macro.include_str.html",
    133    # "iter"
    134    "Iterator": "std/iter/trait.Iterator.html",
    135    "Iter": "std/slice/struct.Iter.html",
    136    "empty": "std/iter/fn.empty.html",
    137    "repeat": "std/iter/fn.repeat.html",
    138    "once": "std/iter/fn.once.html",
    139    "into_iter": "std/iter/trait.IntoIterator.html#tymethod.into_iter",
    140    # errors
    141    "Error": "std/error/trait.Error.html",
    142    "catch_unwind": "std/panic/fn.catch_unwind.html",
    143    # sync
    144    "Lazy": "std/sync/struct.LazyLock.html",
    145    "Once": "std/sync/struct.OnceLock.html",
    146    # convert
    147    "From": "std/convert/trait.From.html",
    148    "TryFrom": "std/convert/trait.TryFrom.html",
    149    "Into": "std/convert/trait.Into.html",
    150    "TryInto": "std/convert/trait.TryInto.html",
    151    "convert_identity": "std/convert/fn.identity.html",
    152    # default
    153    "Default": "std/default/trait.Default.html",
    154    "default_fn": "std/default/trait.Default.html#tymethod.default",
    155    # collections
    156    "HashMap": "std/collections/struct.HashMap.html",
    157    "Vec": "std/vec/struct.Vec.html",
    158    "vec!": "std/macro.vec.html",
    159    # alloc
    160    "String": "alloc/string/struct.String.html",
    161    "ToString": "alloc/string/trait.ToString.html",
    162    # keywords
    163    "unsafe": "std/keyword.unsafe.html",
    164    # primitives
    165    "&[u8]": "std/primitive.slice.html",
    166    "&mut [u8]": "std/primitive.slice.html",
    167    # time
    168    "Duration": "std/time/struct.Duration.html",
    169}
    170
    171_RUSTC_DOCS = "https://doc.rust-lang.org"
    172
    173
    174def _warn(msg: str, stacklevel: int = 2, warn_ty: type[Warning] = Warning) -> None:
    175    warnings.warn(message=msg, stacklevel=stacklevel, category=warn_ty)
    176
    177
    178@functools.cache
    179def _obj_type(obj: type[typing.Any]) -> typing.Literal["class", "function"]:
    180    return "class" if inspect.isclass(obj) else "function"
    181
    182
    183def rustc_diagnostic_item(item: RustItem, /) -> collections.Callable[[T], T]:
    184    '''Expands a Python callable object's documentation, generating the corresponding Rust implementation of the marked object.
    185
    186    This is a decorator that applies on both classes, methods and functions.
    187
    188    Assuming we're implementing the `FnOnce` trait from Rust, the object in Python may be marked with this decorator like this.
    189    ```py
    190    from sain.macros import rustc_diagnostic_item
    191
    192    @rustc_diagnostic_item("FnOnce")
    193    class FnOnce[Output, *Args]:
    194        """The version of the call operator that takes a by-value receiver."""
    195
    196        def __init__(self, fn: Callable[[*Args], Output]) -> None:
    197            self._call = fn
    198
    199        @rustc_diagnostic_item("rust-call")
    200        def call_once(self, *args: *Args) -> Output:
    201            return self._call(*args)
    202    ```
    203
    204    Now that the class is marked,
    205    It will generate documentation that links to the Rust object that we implemented in Python.
    206    '''
    207
    208    def decorator(obj: T) -> T:
    209        additional_doc = f"\n\n# Implementations\nThis {_obj_type(obj)} implements [{item}]({_RUSTC_DOCS}/{_MAP_TO_PATH[item]}) in Rust."
    210        obj.__doc__ = inspect.cleandoc(obj.__doc__ or "") + additional_doc
    211        return obj
    212
    213    return decorator
    214
    215
    216def assert_precondition(
    217    condition: bool,
    218    message: str = "",
    219    exception: type[BaseException] = Exception,
    220) -> None:
    221    """Checks if `condition` is true, raising an exception if not.
    222
    223    This is used to inline check preconditions for functions and methods.
    224
    225    Example
    226    -------
    227    ```py
    228    from sain.macros import assert_precondition
    229
    230    def divide(a: int, b: int) -> float:
    231        assert_precondition(
    232            b != 0,
    233            "b must not be zero",
    234            ZeroDivisionError
    235        )
    236        return a / b
    237    ```
    238
    239    An inlined version would be:
    240    ```py
    241    if not condition:
    242        raise Exception(
    243        f"precondition check violated: {message}"
    244    ) from None
    245    ```
    246
    247    Parameters
    248    ----------
    249    condition : `bool`
    250        The condition to check.
    251    message : `LiteralString`
    252        The message to display if the condition is false.
    253        Defaults to an empty string.
    254    exception : `type[BaseException]`
    255        The exception to raise if the condition is false.
    256        Defaults to `Exception`.
    257    """
    258    if not condition:
    259        raise exception(
    260            f"precondition check violated: \033[91m{message}\033[0m"
    261        ) from None
    262
    263
    264@typing.final
    265class ub_checks(RuntimeWarning):
    266    """A special type of runtime warning that is only invoked on objects using `unsafe`."""
    267
    268
    269def safe(fn: collections.Callable[P, U]) -> collections.Callable[P, U]:
    270    """Permit the use of `unsafe` marked function within a specific object.
    271
    272    This allows you to call functions marked with `unsafe` without causing runtime warnings.
    273
    274    Example
    275    -------
    276    ```py
    277    @unsafe
    278    def unsafe_fn() -> None: ...
    279
    280    @safe
    281    def unsafe_in_safe() -> None:
    282        # Calling this won't cause any runtime warns.
    283        unsafe_fn()
    284
    285    unsafe_in_safe()
    286    ```
    287    """
    288
    289    @functools.wraps(fn)
    290    def wrapper(*args: P.args, **kwargs: P.kwargs) -> U:
    291        if sys.version_info >= (3, 12):
    292            with warnings.catch_warnings(action="ignore", category=ub_checks):
    293                return fn(*args, **kwargs)
    294        else:
    295            with warnings.catch_warnings():
    296                warnings.simplefilter("ignore", category=ub_checks)
    297                return fn(*args, **kwargs)
    298
    299    return wrapper
    300
    301
    302@rustc_diagnostic_item("unsafe")
    303def unsafe(fn: collections.Callable[P, U]) -> collections.Callable[P, U]:
    304    """Mark a function as unsafe.
    305
    306    ## What this marker does
    307    * Generates an unsafe warning to the docstring of the decorated object.
    308    * Warn callers of unsafe usage of an object.
    309    * Never crashes your code, only warns the user, the programmer is responsible
    310    for the code they've written, this is a utility decorator only.
    311
    312    however, ignoring these warnings is possible (*not recommended*), see he listed examples.
    313
    314    Example
    315    -------
    316    Use the `safe` decorator
    317
    318    ```py
    319    @unsafe
    320    def unsafe_fn() -> None: ...
    321
    322    # This decorator desugar into `infallible` in the next example.
    323    @safe
    324    def unsafe_in_safe() -> None:
    325        # Calling this won't cause any runtime warns.
    326        unsafe_fn()
    327
    328    unsafe_in_safe()
    329    ```
    330
    331    Using warnings lib:
    332    ```py
    333    import warnings
    334    from sain.macros import unsafe, ub_checks
    335
    336    # globally ignore all `ub_checks` warns, not recommended.
    337    warnings.filterwarnings("ignore", category=ub_checks)
    338
    339    @unsafe
    340    def from_str_unchecked(val: str) -> float:
    341        return float(val)
    342
    343    # This is a function that calls `from_str_unchecked`
    344    # but we know it will never fails.
    345    def infallible() -> float:
    346        with warnings.catch_warnings():
    347            # ignore `ub_checks` specific warnings from `from_str_unchecked`.
    348            warnings.simplefilter("ignore", category=ub_checks)
    349            return from_str_unchecked("3.14")
    350    ```
    351
    352    Another way is to simply run your program with `-O` opt flag.
    353
    354    This won't generate the code needed to execute the warning,
    355    this will also disable all `assert` calls.
    356
    357    ```sh
    358    # This enable optimization level 1, which will opt-out of `ub_checks` warnings.
    359    python script.py -O
    360    # This will ignore all the warnings.
    361    python -W ignore script.py
    362    ```
    363
    364    The caller of the decorated function is responsible for the undefined behavior if occurred.
    365    """
    366    m = "\n# Safety ⚠️\nCalling this method without knowing the output is considered [undefined behavior](https://en.wikipedia.org/wiki/Undefined_behavior).\n"
    367    if fn.__doc__ is not None:
    368        # append this message to an existing document.
    369        fn.__doc__ = inspect.cleandoc(fn.__doc__) + m
    370    else:
    371        fn.__doc__ = m
    372
    373    if __debug__:
    374
    375        @functools.wraps(fn)
    376        def wrapper(*args: P.args, **kwargs: P.kwargs) -> U:
    377            call_once = fn(*args, **kwargs)
    378            _warn(
    379                f"\033[93mcalling `{wrapper.__qualname__}` "
    380                "is considered unsafe and may lead to undefined behavior.\n"
    381                "you can disable this warning by using `-O` opt level if you know what you're doing.\033[0m",
    382                warn_ty=ub_checks,
    383                stacklevel=3,
    384            )
    385            return call_once
    386
    387        return wrapper
    388    else:
    389        return fn
    390
    391
    392@rustc_diagnostic_item("assert_eq")
    393def assert_eq(left: T, right: T) -> None:
    394    """Asserts that two expressions are equal to each other.
    395
    396    This exactly as `assert left == right`, but includes a useful message in case of failure.
    397
    398    Example
    399    -------
    400    ```py
    401    from sain.macros import assert_eq
    402    a = 3
    403    b = 1 + 2
    404    assert_eq(a, b)
    405    ```
    406    """
    407    assert (
    408        left == right
    409    ), f'assertion `left == right` failed\nleft: "{left!r}"\nright: "{right!r}"'
    410
    411
    412@rustc_diagnostic_item("assert_ne")
    413def assert_ne(left: T, right: T) -> None:
    414    """Asserts that two expressions are not equal to each other.
    415
    416    This exactly as `assert left == right`, but includes a useful message in case of failure.
    417
    418    Example
    419    -------
    420    ```py
    421    from sain.macros import assert_ne
    422    a = 3
    423    b = 2 + 2
    424    assert_ne(a, b)
    425    ```
    426    """
    427    assert (
    428        left != right
    429    ), f'assertion `left != right` failed\nleft: "{left!r}"\nright: "{right!r}"'
    430
    431
    432@rustc_diagnostic_item("include_bytes")
    433def include_bytes(file: LiteralString) -> bytes:
    434    """Includes a file as `bytes`.
    435
    436    This function is not magic, It is literally defined as
    437
    438    ```py
    439    with open(file, "rb") as f:
    440        return f.read()
    441    ```
    442
    443    The file name can may be either a relative to the current file or a complete path.
    444
    445    Example
    446    -------
    447    File "spanish.in":
    448    ```text
    449    adiós
    450    ```
    451    File "main.py":
    452    ```py
    453    from sain.macros import include_bytes
    454    buffer = include_bytes("spanish.in")
    455    assert buffer.decode() == "adiós"
    456    ```
    457    """
    458    with open(file, "rb") as buf:
    459        return buf.read()
    460
    461
    462@rustc_diagnostic_item("include_str")
    463def include_str(file: LiteralString) -> LiteralString:
    464    """Includes a file as literal `str`.
    465
    466    This function is not magic, It is literally defined as
    467
    468    ```py
    469    with open(file, "r") as f:
    470        return f.read()
    471    ```
    472
    473    The file name can may be either a relative to the current file or a complete path.
    474
    475    Example
    476    -------
    477    ```py
    478    from sain.macros import include_str
    479
    480    def entry() -> None:
    481        ...
    482
    483    entry.__doc__ = include_str("README.md")
    484
    485    ```
    486    """
    487    with open(file, "r") as buf:
    488        return buf.read()  # pyright: ignore - simulates a `&'static str` slice.
    489
    490
    491def unstable(
    492    *, reason: LiteralString = "none"
    493) -> collections.Callable[
    494    [collections.Callable[P, typing.Any]],
    495    collections.Callable[P, typing.NoReturn],
    496]:
    497    """A decorator that marks an internal object explicitly unstable.
    498
    499    Unstable objects never ran, even inside the library.
    500
    501    Calling any object that is unstable will raise an `RuntimeError` exception.
    502    Also using this outside the library isn't allowed.
    503
    504    Example
    505    -------
    506    ```py
    507
    508    from sain.macros import unstable
    509
    510    @unstable(reason = "none")
    511    def unstable_function() -> int:
    512        return -1
    513
    514    if unstable_function():
    515        # never reachable
    516
    517    ```
    518    """
    519
    520    def decorator(
    521        obj: collections.Callable[P, U],
    522    ) -> collections.Callable[P, typing.NoReturn]:
    523        @functools.wraps(obj)
    524        def wrapper(*_args: P.args, **_kwargs: P.kwargs) -> typing.NoReturn:
    525            raise RuntimeError(
    526                f"\033[91m{_obj_type(obj)} `{obj.__name__}` is not stable: {reason}.\033[0m"
    527            )
    528
    529        m = (
    530            f"\n# Stability ⚠️\nThis {_obj_type(obj)} is unstable, "
    531            "Calling it may result in failure or [undefined behavior](https://en.wikipedia.org/wiki/Undefined_behavior)."
    532        )
    533        # Append the formatted string to the existing documentation if it exists, otherwise set it as the documentation.
    534        wrapper.__doc__ = (
    535            (inspect.cleandoc(wrapper.__doc__) + m) if wrapper.__doc__ else m
    536        )
    537        return wrapper
    538
    539    return decorator
    540
    541
    542# TODO: in 2.0.0 remove this and use typing_extensions.deprecated instead.
    543@typing.overload
    544def deprecated(
    545    *,
    546    obj: collections.Callable[P, U] | None = None,
    547) -> collections.Callable[P, U]: ...
    548
    549
    550@typing.overload
    551def deprecated(
    552    *,
    553    since: typing.Literal["CURRENT_VERSION"] | LiteralString | None = None,
    554    removed_in: LiteralString | None = None,
    555    use_instead: LiteralString | None = None,
    556    hint: LiteralString | None = None,
    557) -> collections.Callable[
    558    [collections.Callable[P, U]],
    559    collections.Callable[P, U],
    560]: ...
    561
    562
    563@rustc_diagnostic_item("deprecated")
    564def deprecated(
    565    *,
    566    obj: collections.Callable[P, U] | None = None,
    567    since: typing.Literal["CURRENT_VERSION"] | LiteralString | None = None,
    568    removed_in: LiteralString | None = None,
    569    use_instead: LiteralString | None = None,
    570    hint: LiteralString | None = None,
    571) -> (
    572    collections.Callable[P, U]
    573    | collections.Callable[
    574        [collections.Callable[P, U]],
    575        collections.Callable[P, U],
    576    ]
    577):
    578    """A decorator that marks a function as deprecated.
    579
    580    An attempt to call the object that's marked will cause a runtime warn.
    581
    582    Example
    583    -------
    584    ```py
    585    from sain import deprecated
    586
    587    @deprecated(
    588        since = "1.0.0",
    589        removed_in ="3.0.0",
    590        use_instead = "UserImpl()",
    591        hint = "Hint for ux."
    592    )
    593    class User:
    594        # calling the decorator is not necessary.
    595        @deprecated
    596        def username(self) -> str:
    597            ...
    598
    599    user = User() # This will cause a warning at runtime.
    600
    601    ```
    602
    603    Parameters
    604    ----------
    605    since : `str`
    606        The version that the function was deprecated. the `CURRENT_VERSION` is used internally only.
    607    removed_in : `str | None`
    608        If provided, It will log when will the object will be removed in.
    609    use_instead : `str | None`
    610        If provided, This should be the alternative object name that should be used instead.
    611    hint: `str`
    612        An optional hint for the user.
    613    """
    614
    615    def _create_message(
    616        f: typing.Any,
    617    ) -> str:
    618        msg = f"{_obj_type(f)} `{f.__module__}.{f.__name__}` is deprecated."
    619
    620        if since is not None:
    621            if since == "CURRENT_VERSION":
    622                from ._misc import __version__
    623
    624                msg += " since " + __version__
    625            else:
    626                msg += " since " + since
    627
    628        if removed_in:
    629            msg += f" Scheduled for removal in `{removed_in}`."
    630
    631        if use_instead is not None:
    632            msg += f" Use `{use_instead}` instead."
    633
    634        if hint:
    635            msg += f" Hint: {hint}"
    636        return msg
    637
    638    def decorator(func: collections.Callable[P, U]) -> collections.Callable[P, U]:
    639        message = _create_message(func)
    640
    641        @functools.wraps(func)
    642        def wrapper(*args: P.args, **kwargs: P.kwargs) -> U:
    643            _warn("\033[93m" + message + "\033[0m", warn_ty=DeprecationWarning)
    644            return func(*args, **kwargs)
    645
    646        # idk why pyright doesn't know the type of wrapper.
    647        m = f"\n# Warning ⚠️\n{message}."
    648        if wrapper.__doc__:
    649            # append this message to an existing document.
    650            wrapper.__doc__ = inspect.cleandoc(wrapper.__doc__) + f"{m}"
    651        else:
    652            wrapper.__doc__ = m
    653
    654        return wrapper
    655
    656    # marked only.
    657    if obj is not None:
    658        return decorator(obj)
    659
    660    return decorator
    661
    662
    663@rustc_diagnostic_item("todo")
    664def todo(message: LiteralString | None = None) -> typing.NoReturn:
    665    """A place holder that indicates unfinished code.
    666
    667    Example
    668    -------
    669    ```py
    670    from sain import todo
    671
    672    def from_json(payload: dict[str, int]) -> int:
    673        # Calling this function will raise `Error`.
    674        todo()
    675    ```
    676
    677    Parameters
    678    ----------
    679    message : `str | None`
    680        Multiple optional arguments to pass if the error was raised.
    681    """
    682    raise RuntimeWarning(
    683        f"not yet implemented: {message}" if message else "not yet implemented"
    684    )
    685
    686
    687# TODO: in 2.0.0 make this the same as `todo`
    688@typing.overload
    689def unimplemented(
    690    *,
    691    obj: collections.Callable[P, U] | None = None,
    692) -> collections.Callable[P, U]: ...
    693
    694
    695@typing.overload
    696def unimplemented(
    697    *,
    698    message: LiteralString | None = None,
    699    available_in: LiteralString | None = None,
    700) -> collections.Callable[
    701    [collections.Callable[P, U]],
    702    collections.Callable[P, U],
    703]: ...
    704
    705
    706@rustc_diagnostic_item("unimplemented")
    707def unimplemented(
    708    *,
    709    obj: collections.Callable[P, U] | None = None,
    710    message: LiteralString | None = None,
    711    available_in: LiteralString | None = None,
    712) -> (
    713    collections.Callable[P, U]
    714    | collections.Callable[
    715        [collections.Callable[P, U]],
    716        collections.Callable[P, U],
    717    ]
    718):
    719    """A decorator that marks an object as unimplemented.
    720
    721    An attempt to call the object that's marked will cause a runtime warn.
    722
    723    Example
    724    -------
    725    ```py
    726    from sain import unimplemented
    727
    728    @unimplemented  # Can be used without calling
    729    class User:
    730        ...
    731
    732    @unimplemented(message="Not ready", available_in="2.0.0")  # Or with parameters
    733    class Config:
    734        ...
    735    ```
    736
    737    Parameters
    738    ----------
    739    message : `str | None`
    740        An optional message to be displayed when the function is called. Otherwise default message will be used.
    741    available_in : `str | None`
    742        If provided, This will be shown as what release this object be implemented.
    743    """
    744
    745    def _create_message(f: typing.Any) -> str:
    746        msg = (
    747            message
    748            or f"{_obj_type(f)} `{f.__module__}.{f.__name__}` is not yet implemented."
    749        )
    750
    751        if available_in:
    752            msg += f" Available in `{available_in}`."
    753        return msg
    754
    755    def decorator(func: collections.Callable[P, U]) -> collections.Callable[P, U]:
    756        msg = _create_message(func)
    757
    758        @functools.wraps(func)
    759        def wrapper(*args: P.args, **kwargs: P.kwargs) -> U:
    760            _warn("\033[93m" + msg + "\033[0m", warn_ty=RuntimeWarning)
    761            return func(*args, **kwargs)
    762
    763        m = f"\n# Warning ⚠️\n{msg}."
    764        if wrapper.__doc__:
    765            # Append the new documentation string to the existing docstring.
    766            wrapper.__doc__ = inspect.cleandoc(wrapper.__doc__) + m
    767        else:
    768            # Assign the new documentation string as the docstring when no existing docstring is present.
    769            wrapper.__doc__ = m
    770        return wrapper
    771
    772    if obj is not None:
    773        return decorator(obj)
    774
    775    return decorator
    776
    777
    778@rustc_diagnostic_item("doc")
    779def doc(
    780    path: Read,
    781) -> collections.Callable[
    782    [collections.Callable[P, U]],
    783    collections.Callable[P, U],
    784]:
    785    """Set `path` to be the object's documentation.
    786
    787    Example
    788    -------
    789    ```py
    790    from sain import doc
    791    from pathlib import Path
    792
    793    @doc(Path("../README.md"))
    794    class builtins:
    795        @doc("bool.html")
    796        def bool_docs() -> None:
    797            ...
    798    ```
    799
    800    Parameters
    801    ----------
    802    path: `type[int] | type[str] | type[bytes] | type[PathLike[str]] | type[PathLike[bytes]]`
    803        The path to read the content from.
    804    """
    805
    806    def decorator(f: collections.Callable[P, U]) -> collections.Callable[P, U]:
    807        with open(path, "r") as file:
    808            f.__doc__ = file.read()
    809
    810        return lambda *args, **kwargs: f(*args, **kwargs)
    811
    812    return decorator

@rustc_diagnostic_item('deprecated')
def deprecated( *, obj: 'collections.Callable[P, U] | None' = None, since: Union[Literal['CURRENT_VERSION'], LiteralString, NoneType] = None, removed_in: Optional[LiteralString] = None, use_instead: Optional[LiteralString] = None, hint: Optional[LiteralString] = None) -> 'collections.Callable[P, U] | collections.Callable[[collections.Callable[P, U]], collections.Callable[P, U]]': View Source

    564@rustc_diagnostic_item("deprecated")
    565def deprecated(
    566    *,
    567    obj: collections.Callable[P, U] | None = None,
    568    since: typing.Literal["CURRENT_VERSION"] | LiteralString | None = None,
    569    removed_in: LiteralString | None = None,
    570    use_instead: LiteralString | None = None,
    571    hint: LiteralString | None = None,
    572) -> (
    573    collections.Callable[P, U]
    574    | collections.Callable[
    575        [collections.Callable[P, U]],
    576        collections.Callable[P, U],
    577    ]
    578):
    579    """A decorator that marks a function as deprecated.
    580
    581    An attempt to call the object that's marked will cause a runtime warn.
    582
    583    Example
    584    -------
    585    ```py
    586    from sain import deprecated
    587
    588    @deprecated(
    589        since = "1.0.0",
    590        removed_in ="3.0.0",
    591        use_instead = "UserImpl()",
    592        hint = "Hint for ux."
    593    )
    594    class User:
    595        # calling the decorator is not necessary.
    596        @deprecated
    597        def username(self) -> str:
    598            ...
    599
    600    user = User() # This will cause a warning at runtime.
    601
    602    ```
    603
    604    Parameters
    605    ----------
    606    since : `str`
    607        The version that the function was deprecated. the `CURRENT_VERSION` is used internally only.
    608    removed_in : `str | None`
    609        If provided, It will log when will the object will be removed in.
    610    use_instead : `str | None`
    611        If provided, This should be the alternative object name that should be used instead.
    612    hint: `str`
    613        An optional hint for the user.
    614    """
    615
    616    def _create_message(
    617        f: typing.Any,
    618    ) -> str:
    619        msg = f"{_obj_type(f)} `{f.__module__}.{f.__name__}` is deprecated."
    620
    621        if since is not None:
    622            if since == "CURRENT_VERSION":
    623                from ._misc import __version__
    624
    625                msg += " since " + __version__
    626            else:
    627                msg += " since " + since
    628
    629        if removed_in:
    630            msg += f" Scheduled for removal in `{removed_in}`."
    631
    632        if use_instead is not None:
    633            msg += f" Use `{use_instead}` instead."
    634
    635        if hint:
    636            msg += f" Hint: {hint}"
    637        return msg
    638
    639    def decorator(func: collections.Callable[P, U]) -> collections.Callable[P, U]:
    640        message = _create_message(func)
    641
    642        @functools.wraps(func)
    643        def wrapper(*args: P.args, **kwargs: P.kwargs) -> U:
    644            _warn("\033[93m" + message + "\033[0m", warn_ty=DeprecationWarning)
    645            return func(*args, **kwargs)
    646
    647        # idk why pyright doesn't know the type of wrapper.
    648        m = f"\n# Warning ⚠️\n{message}."
    649        if wrapper.__doc__:
    650            # append this message to an existing document.
    651            wrapper.__doc__ = inspect.cleandoc(wrapper.__doc__) + f"{m}"
    652        else:
    653            wrapper.__doc__ = m
    654
    655        return wrapper
    656
    657    # marked only.
    658    if obj is not None:
    659        return decorator(obj)
    660
    661    return decorator

A decorator that marks a function as deprecated.

An attempt to call the object that's marked will cause a runtime warn.

###### Example

    from sain import deprecated

    @deprecated(
        since = "1.0.0",
        removed_in ="3.0.0",
        use_instead = "UserImpl()",
        hint = "Hint for ux."
    )
    class User:
        # calling the decorator is not necessary.
        @deprecated
        def username(self) -> str:
            ...

    user = User() # This will cause a warning at runtime.

###### Parameters

- since (`str`): The version that the function was deprecated. the `CURRENT_VERSION` is used internally only.
- removed_in (`str | None`): If provided, It will log when will the object will be removed in.
- use_instead (`str | None`): If provided, This should be the alternative object name that should be used instead.
- hint (`str`): An optional hint for the user.
- # Implementations
- **This function implements deprecated:

@rustc_diagnostic_item('unimplemented')
def unimplemented( *, obj: 'collections.Callable[P, U] | None' = None, message: Optional[LiteralString] = None, available_in: Optional[LiteralString] = None) -> 'collections.Callable[P, U] | collections.Callable[[collections.Callable[P, U]], collections.Callable[P, U]]': View Source

    707@rustc_diagnostic_item("unimplemented")
    708def unimplemented(
    709    *,
    710    obj: collections.Callable[P, U] | None = None,
    711    message: LiteralString | None = None,
    712    available_in: LiteralString | None = None,
    713) -> (
    714    collections.Callable[P, U]
    715    | collections.Callable[
    716        [collections.Callable[P, U]],
    717        collections.Callable[P, U],
    718    ]
    719):
    720    """A decorator that marks an object as unimplemented.
    721
    722    An attempt to call the object that's marked will cause a runtime warn.
    723
    724    Example
    725    -------
    726    ```py
    727    from sain import unimplemented
    728
    729    @unimplemented  # Can be used without calling
    730    class User:
    731        ...
    732
    733    @unimplemented(message="Not ready", available_in="2.0.0")  # Or with parameters
    734    class Config:
    735        ...
    736    ```
    737
    738    Parameters
    739    ----------
    740    message : `str | None`
    741        An optional message to be displayed when the function is called. Otherwise default message will be used.
    742    available_in : `str | None`
    743        If provided, This will be shown as what release this object be implemented.
    744    """
    745
    746    def _create_message(f: typing.Any) -> str:
    747        msg = (
    748            message
    749            or f"{_obj_type(f)} `{f.__module__}.{f.__name__}` is not yet implemented."
    750        )
    751
    752        if available_in:
    753            msg += f" Available in `{available_in}`."
    754        return msg
    755
    756    def decorator(func: collections.Callable[P, U]) -> collections.Callable[P, U]:
    757        msg = _create_message(func)
    758
    759        @functools.wraps(func)
    760        def wrapper(*args: P.args, **kwargs: P.kwargs) -> U:
    761            _warn("\033[93m" + msg + "\033[0m", warn_ty=RuntimeWarning)
    762            return func(*args, **kwargs)
    763
    764        m = f"\n# Warning ⚠️\n{msg}."
    765        if wrapper.__doc__:
    766            # Append the new documentation string to the existing docstring.
    767            wrapper.__doc__ = inspect.cleandoc(wrapper.__doc__) + m
    768        else:
    769            # Assign the new documentation string as the docstring when no existing docstring is present.
    770            wrapper.__doc__ = m
    771        return wrapper
    772
    773    if obj is not None:
    774        return decorator(obj)
    775
    776    return decorator

A decorator that marks an object as unimplemented.

An attempt to call the object that's marked will cause a runtime warn.

###### Example

    from sain import unimplemented

    @unimplemented  # Can be used without calling
    class User:
        ...

    @unimplemented(message="Not ready", available_in="2.0.0")  # Or with parameters
    class Config:
        ...

###### Parameters

- message (`str | None`): An optional message to be displayed when the function is called. Otherwise default message will be used.
- available_in (`str | None`): If provided, This will be shown as what release this object be implemented.
- # Implementations
- **This function implements unimplemented:

@rustc_diagnostic_item('todo')
def todo(message: Optional[LiteralString] = None) -> NoReturn: View Source

    664@rustc_diagnostic_item("todo")
    665def todo(message: LiteralString | None = None) -> typing.NoReturn:
    666    """A place holder that indicates unfinished code.
    667
    668    Example
    669    -------
    670    ```py
    671    from sain import todo
    672
    673    def from_json(payload: dict[str, int]) -> int:
    674        # Calling this function will raise `Error`.
    675        todo()
    676    ```
    677
    678    Parameters
    679    ----------
    680    message : `str | None`
    681        Multiple optional arguments to pass if the error was raised.
    682    """
    683    raise RuntimeWarning(
    684        f"not yet implemented: {message}" if message else "not yet implemented"
    685    )

A place holder that indicates unfinished code.

###### Example

    from sain import todo

    def from_json(payload: dict[str, int]) -> int:
        # Calling this function will raise `Error`.
        todo()

###### Parameters

- message (`str | None`): Multiple optional arguments to pass if the error was raised.
- # Implementations
- **This function implements todo:

@rustc_diagnostic_item('doc')
def doc( path: 'Read') -> 'collections.Callable[[collections.Callable[P, U]], collections.Callable[P, U]]': View Source

    779@rustc_diagnostic_item("doc")
    780def doc(
    781    path: Read,
    782) -> collections.Callable[
    783    [collections.Callable[P, U]],
    784    collections.Callable[P, U],
    785]:
    786    """Set `path` to be the object's documentation.
    787
    788    Example
    789    -------
    790    ```py
    791    from sain import doc
    792    from pathlib import Path
    793
    794    @doc(Path("../README.md"))
    795    class builtins:
    796        @doc("bool.html")
    797        def bool_docs() -> None:
    798            ...
    799    ```
    800
    801    Parameters
    802    ----------
    803    path: `type[int] | type[str] | type[bytes] | type[PathLike[str]] | type[PathLike[bytes]]`
    804        The path to read the content from.
    805    """
    806
    807    def decorator(f: collections.Callable[P, U]) -> collections.Callable[P, U]:
    808        with open(path, "r") as file:
    809            f.__doc__ = file.read()
    810
    811        return lambda *args, **kwargs: f(*args, **kwargs)
    812
    813    return decorator

Set `path` to be the object's documentation.

###### Example

    from sain import doc
    from pathlib import Path

    @doc(Path("../README.md"))
    class builtins:
        @doc("bool.html")
        def bool_docs() -> None:
            ...

###### Parameters

- path (`type[int] | type[str] | type[bytes] | type[PathLike[str]] | type[PathLike[bytes]]`): The path to read the content from.
- # Implementations
- **This function implements doc:

@rustc_diagnostic_item('assert_eq')
def assert_eq(left: +T, right: +T) -> None: View Source

    393@rustc_diagnostic_item("assert_eq")
    394def assert_eq(left: T, right: T) -> None:
    395    """Asserts that two expressions are equal to each other.
    396
    397    This exactly as `assert left == right`, but includes a useful message in case of failure.
    398
    399    Example
    400    -------
    401    ```py
    402    from sain.macros import assert_eq
    403    a = 3
    404    b = 1 + 2
    405    assert_eq(a, b)
    406    ```
    407    """
    408    assert (
    409        left == right
    410    ), f'assertion `left == right` failed\nleft: "{left!r}"\nright: "{right!r}"'

Asserts that two expressions are equal to each other.

This exactly as `assert left == right`, but includes a useful message in case of failure.

###### Example

    from sain.macros import assert_eq
    a = 3
    b = 1 + 2
    assert_eq(a, b)

# Implementations

This function implements assert_eq in Rust.

@rustc_diagnostic_item('assert_ne')
def assert_ne(left: +T, right: +T) -> None: View Source

    413@rustc_diagnostic_item("assert_ne")
    414def assert_ne(left: T, right: T) -> None:
    415    """Asserts that two expressions are not equal to each other.
    416
    417    This exactly as `assert left == right`, but includes a useful message in case of failure.
    418
    419    Example
    420    -------
    421    ```py
    422    from sain.macros import assert_ne
    423    a = 3
    424    b = 2 + 2
    425    assert_ne(a, b)
    426    ```
    427    """
    428    assert (
    429        left != right
    430    ), f'assertion `left != right` failed\nleft: "{left!r}"\nright: "{right!r}"'

Asserts that two expressions are not equal to each other.

This exactly as `assert left == right`, but includes a useful message in case of failure.

###### Example

    from sain.macros import assert_ne
    a = 3
    b = 2 + 2
    assert_ne(a, b)

# Implementations

This function implements assert_ne in Rust.

@rustc_diagnostic_item('include_str')
def include_str(file: LiteralString) -> LiteralString: View Source

    463@rustc_diagnostic_item("include_str")
    464def include_str(file: LiteralString) -> LiteralString:
    465    """Includes a file as literal `str`.
    466
    467    This function is not magic, It is literally defined as
    468
    469    ```py
    470    with open(file, "r") as f:
    471        return f.read()
    472    ```
    473
    474    The file name can may be either a relative to the current file or a complete path.
    475
    476    Example
    477    -------
    478    ```py
    479    from sain.macros import include_str
    480
    481    def entry() -> None:
    482        ...
    483
    484    entry.__doc__ = include_str("README.md")
    485
    486    ```
    487    """
    488    with open(file, "r") as buf:
    489        return buf.read()  # pyright: ignore - simulates a `&'static str` slice.

Includes a file as literal `str`.

This function is not magic, It is literally defined as

    with open(file, "r") as f:
        return f.read()

The file name can may be either a relative to the current file or a complete path.

###### Example

    from sain.macros import include_str

    def entry() -> None:
        ...

    entry.__doc__ = include_str("README.md")

# Implementations

This function implements include_str in Rust.

@rustc_diagnostic_item('include_bytes')
def include_bytes(file: LiteralString) -> bytes: View Source

    433@rustc_diagnostic_item("include_bytes")
    434def include_bytes(file: LiteralString) -> bytes:
    435    """Includes a file as `bytes`.
    436
    437    This function is not magic, It is literally defined as
    438
    439    ```py
    440    with open(file, "rb") as f:
    441        return f.read()
    442    ```
    443
    444    The file name can may be either a relative to the current file or a complete path.
    445
    446    Example
    447    -------
    448    File "spanish.in":
    449    ```text
    450    adiós
    451    ```
    452    File "main.py":
    453    ```py
    454    from sain.macros import include_bytes
    455    buffer = include_bytes("spanish.in")
    456    assert buffer.decode() == "adiós"
    457    ```
    458    """
    459    with open(file, "rb") as buf:
    460        return buf.read()

Includes a file as `bytes`.

This function is not magic, It is literally defined as

    with open(file, "rb") as f:
        return f.read()

The file name can may be either a relative to the current file or a complete path.

###### Example

File "spanish.in":

    adiós

File "main.py":

    from sain.macros import include_bytes
    buffer = include_bytes("spanish.in")
    assert buffer.decode() == "adiós"

# Implementations

This function implements include_bytes in Rust.

def safe(fn: 'collections.Callable[P, U]') -> 'collections.Callable[P, U]': View Source

    270def safe(fn: collections.Callable[P, U]) -> collections.Callable[P, U]:
    271    """Permit the use of `unsafe` marked function within a specific object.
    272
    273    This allows you to call functions marked with `unsafe` without causing runtime warnings.
    274
    275    Example
    276    -------
    277    ```py
    278    @unsafe
    279    def unsafe_fn() -> None: ...
    280
    281    @safe
    282    def unsafe_in_safe() -> None:
    283        # Calling this won't cause any runtime warns.
    284        unsafe_fn()
    285
    286    unsafe_in_safe()
    287    ```
    288    """
    289
    290    @functools.wraps(fn)
    291    def wrapper(*args: P.args, **kwargs: P.kwargs) -> U:
    292        if sys.version_info >= (3, 12):
    293            with warnings.catch_warnings(action="ignore", category=ub_checks):
    294                return fn(*args, **kwargs)
    295        else:
    296            with warnings.catch_warnings():
    297                warnings.simplefilter("ignore", category=ub_checks)
    298                return fn(*args, **kwargs)
    299
    300    return wrapper

Permit the use of `unsafe` marked function within a specific object.

This allows you to call functions marked with `unsafe` without causing runtime warnings.

###### Example

    @unsafe
    def unsafe_fn() -> None: ...

    @safe
    def unsafe_in_safe() -> None:
        # Calling this won't cause any runtime warns.
        unsafe_fn()

    unsafe_in_safe()

@rustc_diagnostic_item('unsafe')
def unsafe(fn: 'collections.Callable[P, U]') -> 'collections.Callable[P, U]': View Source

    303@rustc_diagnostic_item("unsafe")
    304def unsafe(fn: collections.Callable[P, U]) -> collections.Callable[P, U]:
    305    """Mark a function as unsafe.
    306
    307    ## What this marker does
    308    * Generates an unsafe warning to the docstring of the decorated object.
    309    * Warn callers of unsafe usage of an object.
    310    * Never crashes your code, only warns the user, the programmer is responsible
    311    for the code they've written, this is a utility decorator only.
    312
    313    however, ignoring these warnings is possible (*not recommended*), see he listed examples.
    314
    315    Example
    316    -------
    317    Use the `safe` decorator
    318
    319    ```py
    320    @unsafe
    321    def unsafe_fn() -> None: ...
    322
    323    # This decorator desugar into `infallible` in the next example.
    324    @safe
    325    def unsafe_in_safe() -> None:
    326        # Calling this won't cause any runtime warns.
    327        unsafe_fn()
    328
    329    unsafe_in_safe()
    330    ```
    331
    332    Using warnings lib:
    333    ```py
    334    import warnings
    335    from sain.macros import unsafe, ub_checks
    336
    337    # globally ignore all `ub_checks` warns, not recommended.
    338    warnings.filterwarnings("ignore", category=ub_checks)
    339
    340    @unsafe
    341    def from_str_unchecked(val: str) -> float:
    342        return float(val)
    343
    344    # This is a function that calls `from_str_unchecked`
    345    # but we know it will never fails.
    346    def infallible() -> float:
    347        with warnings.catch_warnings():
    348            # ignore `ub_checks` specific warnings from `from_str_unchecked`.
    349            warnings.simplefilter("ignore", category=ub_checks)
    350            return from_str_unchecked("3.14")
    351    ```
    352
    353    Another way is to simply run your program with `-O` opt flag.
    354
    355    This won't generate the code needed to execute the warning,
    356    this will also disable all `assert` calls.
    357
    358    ```sh
    359    # This enable optimization level 1, which will opt-out of `ub_checks` warnings.
    360    python script.py -O
    361    # This will ignore all the warnings.
    362    python -W ignore script.py
    363    ```
    364
    365    The caller of the decorated function is responsible for the undefined behavior if occurred.
    366    """
    367    m = "\n# Safety ⚠️\nCalling this method without knowing the output is considered [undefined behavior](https://en.wikipedia.org/wiki/Undefined_behavior).\n"
    368    if fn.__doc__ is not None:
    369        # append this message to an existing document.
    370        fn.__doc__ = inspect.cleandoc(fn.__doc__) + m
    371    else:
    372        fn.__doc__ = m
    373
    374    if __debug__:
    375
    376        @functools.wraps(fn)
    377        def wrapper(*args: P.args, **kwargs: P.kwargs) -> U:
    378            call_once = fn(*args, **kwargs)
    379            _warn(
    380                f"\033[93mcalling `{wrapper.__qualname__}` "
    381                "is considered unsafe and may lead to undefined behavior.\n"
    382                "you can disable this warning by using `-O` opt level if you know what you're doing.\033[0m",
    383                warn_ty=ub_checks,
    384                stacklevel=3,
    385            )
    386            return call_once
    387
    388        return wrapper
    389    else:
    390        return fn

Mark a function as unsafe.

## What this marker does

- Generates an unsafe warning to the docstring of the decorated object.
- Warn callers of unsafe usage of an object.
- Never crashes your code, only warns the user, the programmer is responsible for the code they've written, this is a utility decorator only.

however, ignoring these warnings is possible (not recommended), see he listed examples.

###### Example

Use the `safe` decorator

    @unsafe
    def unsafe_fn() -> None: ...

    # This decorator desugar into `infallible` in the next example.
    @safe
    def unsafe_in_safe() -> None:
        # Calling this won't cause any runtime warns.
        unsafe_fn()

    unsafe_in_safe()

Using warnings lib:

    import warnings
    from sain.macros import unsafe, ub_checks

    # globally ignore all `ub_checks` warns, not recommended.
    warnings.filterwarnings("ignore", category=ub_checks)

    @unsafe
    def from_str_unchecked(val: str) -> float:
        return float(val)

    # This is a function that calls `from_str_unchecked`
    # but we know it will never fails.
    def infallible() -> float:
        with warnings.catch_warnings():
            # ignore `ub_checks` specific warnings from `from_str_unchecked`.
            warnings.simplefilter("ignore", category=ub_checks)
            return from_str_unchecked("3.14")

Another way is to simply run your program with `-O` opt flag.

This won't generate the code needed to execute the warning, this will also disable all `assert` calls.

    # This enable optimization level 1, which will opt-out of `ub_checks` warnings.
    python script.py -O
    # This will ignore all the warnings.
    python -W ignore script.py

The caller of the decorated function is responsible for the undefined behavior if occurred.

# Implementations

This function implements unsafe in Rust.

def rustc_diagnostic_item(item: 'RustItem', /) -> Callable[[+T], +T]: View Source

    184def rustc_diagnostic_item(item: RustItem, /) -> collections.Callable[[T], T]:
    185    '''Expands a Python callable object's documentation, generating the corresponding Rust implementation of the marked object.
    186
    187    This is a decorator that applies on both classes, methods and functions.
    188
    189    Assuming we're implementing the `FnOnce` trait from Rust, the object in Python may be marked with this decorator like this.
    190    ```py
    191    from sain.macros import rustc_diagnostic_item
    192
    193    @rustc_diagnostic_item("FnOnce")
    194    class FnOnce[Output, *Args]:
    195        """The version of the call operator that takes a by-value receiver."""
    196
    197        def __init__(self, fn: Callable[[*Args], Output]) -> None:
    198            self._call = fn
    199
    200        @rustc_diagnostic_item("rust-call")
    201        def call_once(self, *args: *Args) -> Output:
    202            return self._call(*args)
    203    ```
    204
    205    Now that the class is marked,
    206    It will generate documentation that links to the Rust object that we implemented in Python.
    207    '''
    208
    209    def decorator(obj: T) -> T:
    210        additional_doc = f"\n\n# Implementations\nThis {_obj_type(obj)} implements [{item}]({_RUSTC_DOCS}/{_MAP_TO_PATH[item]}) in Rust."
    211        obj.__doc__ = inspect.cleandoc(obj.__doc__ or "") + additional_doc
    212        return obj
    213
    214    return decorator

Expands a Python callable object's documentation, generating the corresponding Rust implementation of the marked object.

This is a decorator that applies on both classes, methods and functions.

Assuming we're implementing the `FnOnce` trait from Rust, the object in Python may be marked with this decorator like this.

    from sain.macros import rustc_diagnostic_item

    @rustc_diagnostic_item("FnOnce")
    class FnOnce[Output, *Args]:
        """The version of the call operator that takes a by-value receiver."""

        def __init__(self, fn: Callable[[*Args], Output]) -> None:
            self._call = fn

        @rustc_diagnostic_item("rust-call")
        def call_once(self, *args: *Args) -> Output:
            return self._call(*args)

Now that the class is marked, It will generate documentation that links to the Rust object that we implemented in Python.

RustItem