sain


Namesain JSON
Version 1.2.0 PyPI version JSON
download
home_pagehttps://github.com/nxtlo/sain
SummaryStandard Rust core types implementations for Python.
upload_time2024-09-09 11:55:18
maintainerNone
docs_urlNone
authornxtlo
requires_pythonNone
licenseBSD-3-Clause license
keywords rust config typing utilities
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # sain

a dependency-free library which implements a few of Rust's core crates purely in Python.
It offers a few of the core Rust features such as `Vec<T>`, `Result<T, E>`, `Option<T>` and more. See the equivalent type section below.

a few `std` types are implemented. Check the [project documentation](https://nxtlo.github.io/sain/sain.html)

## Install

You'll need Python 3.10 or higher.

PyPI

```sh
pip install sain
```

## Overview

More examples in [examples](https://github.com/nxtlo/sain/tree/master/examples)

### no `try/except`

Rust doesn't have exception, But `Option<T>` which handles None's, and `Result<T, E>` for returning and propagating errors.
we can easily achieve the same results in Python

```py
from __future__ import annotations

from sain import Option, Result, Ok, Err
from sain.collections import Vec, Bytes
from sain.convert import Into

from dataclasses import dataclass, field


# A chunk of data. the from protocol allows users to convert the chunk into bytes.
# similar to Rust's Into trait.
@dataclass
class Chunk(Into[bytes]):
    tag: str
    data: Bytes

    # convert a chunk into bytes.
    # in Rust, this consumes `self`, But in Python it copies it.
    def into(self) -> bytes:
        return self.data.to_bytes()


@dataclass
class BlobStore:
    pos: int
    # A buffer that contains chunks of bytes over which we might
    # lazily load from somewhere. This buffer can hold up to 1024 chunks.
    buffer: Vec[Chunk] = field(default_factory=lambda: Vec[Chunk].with_capacity(1024))

    def put(self, tag: str, data: bytes) -> Result[None, str]:
        chunk = Chunk(tag, Bytes.from_bytes(data))
        # push_within_capacity returns `Result[None, Chunk]`.
        # It returns the chunk that got failed to be pushed,
        # we try to push if there's space, mapping the error to
        # a string.
        return self.buffer.push_within_capacity(chunk).map_err(
            lambda chunk: "No more capacity to push chunk: " + str(chunk)
        )

    def next_chunk(self) -> Option[Chunk]:
        chunk = self.buffer.get(self.pos)
        self.pos += 1
        return chunk


def main() -> None:
    blobs = BlobStore(0)

    # upload a blob matching any errors.
    match blobs.put("c1", b"first chunk"):
        case Ok(_):
            print("chunk pushed succefully.")
        case Err(why):
            print(why)

    # or just
    blobs.put("c2", b"second chunk").unwrap()

    # Read back the chunks, and map it to string.
    # In rust, you would do something similar to
    # * while let Some(chunk) = option.map(String::from_utf8_lossy) { ... } *
    while (chunk := blobs.next_chunk()).is_some():
        print(chunk.map(Chunk.into))

    # use an iterator over the chunks
    for pos, chunk in blobs.buffer.iter().enumerate():
        print(pos, chunk.data)


```

## built-in types

| name in Rust                  | name in Python                   | note                                                                                                                       | restrictions               |
| ----------------------------- | -------------------------------  | -------------------------------------------------------------------------------------------------------------------------- | -------------------------- |
| Option\<T>, Some(T), None     | Option[T], Some(T), Some(None)   | Some(None) has the same layout as `None` in Rust                                                                           |                            |
| Result\<T, E>, Ok(T), Err(E)  | Result[T, E], Ok(T), Err(E)      |                                                                                                                            |                            |
| Vec\<T>                       | Vec[T]                           |                                                                                                                            |                            |
| HashMap\<K, V>                      | HashMap[K, V]                          |                                                                                      |                            |
| bytes::Bytes                      |  Bytes                          |                                                                                      |                            |
| LazyLock\<T>                  | Lazy[T]                          |                                                                                                                            |                            |
| OnceLock\<T>                  | Once[T]                          |                                                                                                                            |                            |
| Box\<T>                       | Box[T]                           | this isn't a heap box, [See]([https://nxtlo.github.io/sain/sain/boxed.html](https://nxtlo.github.io/sain/sain/boxed.html)) |                            |
| MaybeUninit\<T>               | MaybeUninit[T]                   | they serve the same purpose, but slightly different                                                                        |                            |
| &dyn Default                       | Default[T]                       |                                                                                                                            |                            |
| &dyn Error                    | Error                            |                                                                                                                            |                            |
| &dyn Iterator\<T>                  | Iterator[T]                      |                                                                                                                            |                            |
| Iter\<'a, T>                  | Iter[T]                          | collections called by `.iter()` are built from this type                                                                     |                            |
| iter::once::\<T>()            | iter.once[T]                     |                                                                                                                            |                            |
| iter::empty::\<T>()           | iter.empty[T]                    |                                                                                                                            |                            |
| iter::repeat::\<T>()          | iter.repeat[T]                   |                                                                                                                            |                            |
| cfg!()                        | cfg()                            | runtime cfg, not all predictions are supported                                                                             |                            |
| #[cfg_attr]                   | @cfg_attr()                      | runtime cfg, not all predictions are supported                                                                             |                            |
| #[doc]                        | @doc()                           | the docs get generated at runtime                                                                                          |                            |
| todo!()                       | todo()                           |                                                                                                                            |                            |
| #[deprecated]                 | @deprecated()                    | will get removed when it get stabilized in `warnings` in Python `3.13`                                                     |                            |
| unimplemented!()              | @unimplemented()                 |                                                                                                                            |                            |

## Notes

Since Rust is a compiled language, Whatever predict in `cfg` and `cfg_attr` returns False will not compile.

But there's no such thing as this in Python, So `RuntimeError` will be raised and whatever was predicated will not run.

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/nxtlo/sain",
    "name": "sain",
    "maintainer": null,
    "docs_url": null,
    "requires_python": null,
    "maintainer_email": null,
    "keywords": "Rust, config, typing, utilities",
    "author": "nxtlo",
    "author_email": "dhmony-99@hotmail.com",
    "download_url": "https://files.pythonhosted.org/packages/49/f4/90661061ca6a10c602c5f02b7b2c7206bd2b741aace1d34ca27335d46380/sain-1.2.0.tar.gz",
    "platform": null,
    "description": "# sain\n\na dependency-free library which implements a few of Rust's core crates purely in Python.\nIt offers a few of the core Rust features such as `Vec<T>`, `Result<T, E>`, `Option<T>` and more. See the equivalent type section below.\n\na few `std` types are implemented. Check the [project documentation](https://nxtlo.github.io/sain/sain.html)\n\n## Install\n\nYou'll need Python 3.10 or higher.\n\nPyPI\n\n```sh\npip install sain\n```\n\n## Overview\n\nMore examples in [examples](https://github.com/nxtlo/sain/tree/master/examples)\n\n### no `try/except`\n\nRust doesn't have exception, But `Option<T>` which handles None's, and `Result<T, E>` for returning and propagating errors.\nwe can easily achieve the same results in Python\n\n```py\nfrom __future__ import annotations\n\nfrom sain import Option, Result, Ok, Err\nfrom sain.collections import Vec, Bytes\nfrom sain.convert import Into\n\nfrom dataclasses import dataclass, field\n\n\n# A chunk of data. the from protocol allows users to convert the chunk into bytes.\n# similar to Rust's Into trait.\n@dataclass\nclass Chunk(Into[bytes]):\n    tag: str\n    data: Bytes\n\n    # convert a chunk into bytes.\n    # in Rust, this consumes `self`, But in Python it copies it.\n    def into(self) -> bytes:\n        return self.data.to_bytes()\n\n\n@dataclass\nclass BlobStore:\n    pos: int\n    # A buffer that contains chunks of bytes over which we might\n    # lazily load from somewhere. This buffer can hold up to 1024 chunks.\n    buffer: Vec[Chunk] = field(default_factory=lambda: Vec[Chunk].with_capacity(1024))\n\n    def put(self, tag: str, data: bytes) -> Result[None, str]:\n        chunk = Chunk(tag, Bytes.from_bytes(data))\n        # push_within_capacity returns `Result[None, Chunk]`.\n        # It returns the chunk that got failed to be pushed,\n        # we try to push if there's space, mapping the error to\n        # a string.\n        return self.buffer.push_within_capacity(chunk).map_err(\n            lambda chunk: \"No more capacity to push chunk: \" + str(chunk)\n        )\n\n    def next_chunk(self) -> Option[Chunk]:\n        chunk = self.buffer.get(self.pos)\n        self.pos += 1\n        return chunk\n\n\ndef main() -> None:\n    blobs = BlobStore(0)\n\n    # upload a blob matching any errors.\n    match blobs.put(\"c1\", b\"first chunk\"):\n        case Ok(_):\n            print(\"chunk pushed succefully.\")\n        case Err(why):\n            print(why)\n\n    # or just\n    blobs.put(\"c2\", b\"second chunk\").unwrap()\n\n    # Read back the chunks, and map it to string.\n    # In rust, you would do something similar to\n    # * while let Some(chunk) = option.map(String::from_utf8_lossy) { ... } *\n    while (chunk := blobs.next_chunk()).is_some():\n        print(chunk.map(Chunk.into))\n\n    # use an iterator over the chunks\n    for pos, chunk in blobs.buffer.iter().enumerate():\n        print(pos, chunk.data)\n\n\n```\n\n## built-in types\n\n| name in Rust                  | name in Python                   | note                                                                                                                       | restrictions               |\n| ----------------------------- | -------------------------------  | -------------------------------------------------------------------------------------------------------------------------- | -------------------------- |\n| Option\\<T>, Some(T), None     | Option[T], Some(T), Some(None)   | Some(None) has the same layout as `None` in Rust                                                                           |                            |\n| Result\\<T, E>, Ok(T), Err(E)  | Result[T, E], Ok(T), Err(E)      |                                                                                                                            |                            |\n| Vec\\<T>                       | Vec[T]                           |                                                                                                                            |                            |\n| HashMap\\<K, V>                      | HashMap[K, V]                          |                                                                                      |                            |\n| bytes::Bytes                      |  Bytes                          |                                                                                      |                            |\n| LazyLock\\<T>                  | Lazy[T]                          |                                                                                                                            |                            |\n| OnceLock\\<T>                  | Once[T]                          |                                                                                                                            |                            |\n| Box\\<T>                       | Box[T]                           | this isn't a heap box, [See]([https://nxtlo.github.io/sain/sain/boxed.html](https://nxtlo.github.io/sain/sain/boxed.html)) |                            |\n| MaybeUninit\\<T>               | MaybeUninit[T]                   | they serve the same purpose, but slightly different                                                                        |                            |\n| &dyn Default                       | Default[T]                       |                                                                                                                            |                            |\n| &dyn Error                    | Error                            |                                                                                                                            |                            |\n| &dyn Iterator\\<T>                  | Iterator[T]                      |                                                                                                                            |                            |\n| Iter\\<'a, T>                  | Iter[T]                          | collections called by `.iter()`\u00a0are built from this type                                                                     |                            |\n| iter::once::\\<T>()            | iter.once[T]                     |                                                                                                                            |                            |\n| iter::empty::\\<T>()           | iter.empty[T]                    |                                                                                                                            |                            |\n| iter::repeat::\\<T>()          | iter.repeat[T]                   |                                                                                                                            |                            |\n| cfg!()                        | cfg()                            | runtime cfg, not all predictions are supported                                                                             |                            |\n| #[cfg_attr]                   | @cfg_attr()                      | runtime cfg, not all predictions are supported                                                                             |                            |\n| #[doc]                        | @doc()                           | the docs get generated at runtime                                                                                          |                            |\n| todo!()                       | todo()                           |                                                                                                                            |                            |\n| #[deprecated]                 | @deprecated()                    | will get removed when it get stabilized in `warnings`\u00a0in Python `3.13`                                                     |                            |\n| unimplemented!()              | @unimplemented()                 |                                                                                                                            |                            |\n\n## Notes\n\nSince Rust is a compiled language, Whatever predict in `cfg` and `cfg_attr` returns False will not compile.\n\nBut there's no such thing as this in Python, So `RuntimeError` will be raised and whatever was predicated will not run.\n",
    "bugtrack_url": null,
    "license": "BSD-3-Clause license",
    "summary": "Standard Rust core types implementations for Python.",
    "version": "1.2.0",
    "project_urls": {
        "Homepage": "https://github.com/nxtlo/sain",
        "Repository": "https://github.com/nxtlo/sain"
    },
    "split_keywords": [
        "rust",
        " config",
        " typing",
        " utilities"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "107f5dc6c5d3cb5f0505c26d81396ddf3d9d94b0f8b115c0f4441e046ac49832",
                "md5": "28fbdd76d6f0fea63567fe5c7d1a594c",
                "sha256": "c335868ecbcfadccc0414f7ecc96b91387ca15a92d1b15c0211adb6c07f3e422"
            },
            "downloads": -1,
            "filename": "sain-1.2.0-py2.py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "28fbdd76d6f0fea63567fe5c7d1a594c",
            "packagetype": "bdist_wheel",
            "python_version": "py2.py3",
            "requires_python": null,
            "size": 69045,
            "upload_time": "2024-09-09T11:55:16",
            "upload_time_iso_8601": "2024-09-09T11:55:16.948969Z",
            "url": "https://files.pythonhosted.org/packages/10/7f/5dc6c5d3cb5f0505c26d81396ddf3d9d94b0f8b115c0f4441e046ac49832/sain-1.2.0-py2.py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "49f490661061ca6a10c602c5f02b7b2c7206bd2b741aace1d34ca27335d46380",
                "md5": "ed4dc09d458ed688bdc2a409c6f0ee26",
                "sha256": "45ffb3b4ab55b0a76793596c389837e44a3d05b11408b9644481d6acbeb96895"
            },
            "downloads": -1,
            "filename": "sain-1.2.0.tar.gz",
            "has_sig": false,
            "md5_digest": "ed4dc09d458ed688bdc2a409c6f0ee26",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": null,
            "size": 46213,
            "upload_time": "2024-09-09T11:55:18",
            "upload_time_iso_8601": "2024-09-09T11:55:18.727498Z",
            "url": "https://files.pythonhosted.org/packages/49/f4/90661061ca6a10c602c5f02b7b2c7206bd2b741aace1d34ca27335d46380/sain-1.2.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-09-09 11:55:18",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "nxtlo",
    "github_project": "sain",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "sain"
}
        
Elapsed time: 2.47188s