From 78ed43ac723c0ff7f12574ea992b4bff4a34d9e5 Mon Sep 17 00:00:00 2001 From: Felix Schorer Date: Tue, 14 Jan 2020 04:58:01 +0100 Subject: [PATCH] feat: Add CPython wrapper (#33) * Add CPython wrapper * Add CPython wrapper to build pipeline * Don't use Travis CI matrix expansion * Install maturin and add cache * Install Python * Install fix incorrect package name 'pip3' * Update package list * Split build in two jobs * Don't cache as installing lichking will error otherwise * Don't lint on nightly * Add Python tests * Add venv * Fix execution order * Run linter * Run linter --- .travis.yml | 46 ++++-- examples/main.py | 38 +++++ python/.cargo/config | 5 + python/.gitignore | 1 + python/Cargo.lock | 326 ++++++++++++++++++++++++++++++++++++++++ python/Cargo.toml | 20 +++ python/Makefile | 15 ++ python/README.md | 19 +++ python/pyproject.toml | 3 + python/src/lib.rs | 74 +++++++++ python/test/__init__.py | 35 +++++ 11 files changed, 573 insertions(+), 9 deletions(-) create mode 100644 examples/main.py create mode 100644 python/.cargo/config create mode 100644 python/.gitignore create mode 100644 python/Cargo.lock create mode 100644 python/Cargo.toml create mode 100644 python/Makefile create mode 100644 python/README.md create mode 100644 python/pyproject.toml create mode 100644 python/src/lib.rs create mode 100644 python/test/__init__.py diff --git a/.travis.yml b/.travis.yml index 53e8ef7..360b617 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,9 +1,37 @@ -language: rust -rust: - - stable -before_script: - - cargo install cargo-lichking - - rustup component add rustfmt - - rustup component add clippy -script: - - make test +matrix: + fast_finish: true + include: + - name: Run tests + language: rust + rust: stable + install: + [] + before_script: + - cargo install cargo-lichking + - rustup component add rustfmt + - rustup component add clippy + script: + - make test + + - name: Run CPython wrapper linter + language: rust + rust: stable + install: + [] + before_script: + - cargo install cargo-lichking + - rustup component add rustfmt + script: + - make -C python lint + + - name: Run CPython wrapper tests + language: rust + rust: nightly + install: + [] + before_script: + - sudo apt update && sudo apt install python3 python3-pip python3-dev + - pip3 install virtualenv maturin + - python3 -m virtualenv venv + script: + - source venv/bin/activate && make -C python test diff --git a/examples/main.py b/examples/main.py new file mode 100644 index 0000000..413fe05 --- /dev/null +++ b/examples/main.py @@ -0,0 +1,38 @@ +import os +import random +from raptorq import Encoder, Decoder + + +def main(): + # Generate some random data to send + data = os.urandom(10000) + + # Create the Encoder, with an MTU of 1400 (common for Ethernet) + encoder = Encoder.with_defaults(data, 1400) + + # Perform the encoding, and serialize to bytes for transmission + packets = encoder.get_encoded_packets(15) + + # Here we simulate losing 10 of the packets randomly. Normally, you would send them over + # (potentially lossy) network here. + random.shuffle(packets) + # Erase 10 packets at random + packets = packets[:-10] + + # The Decoder MUST be constructed with the configuration of the Encoder. + # The configuration should be transmitted over a reliable channel + decoder = Decoder.with_defaults(len(data), 1400) + + # Perform the decoding + result = None + for packet in packets: + result = decoder.decode(packet) + if result is not None: + break + + # Check that even though some of the data was lost we are able to reconstruct the original message + assert result == data + + +if __name__ == '__main__': + main() diff --git a/python/.cargo/config b/python/.cargo/config new file mode 100644 index 0000000..58103f6 --- /dev/null +++ b/python/.cargo/config @@ -0,0 +1,5 @@ +[target.x86_64-apple-darwin] +rustflags = [ + "-C", "link-arg=-undefined", + "-C", "link-arg=dynamic_lookup", +] \ No newline at end of file diff --git a/python/.gitignore b/python/.gitignore new file mode 100644 index 0000000..a6f89c2 --- /dev/null +++ b/python/.gitignore @@ -0,0 +1 @@ +/target/ \ No newline at end of file diff --git a/python/Cargo.lock b/python/Cargo.lock new file mode 100644 index 0000000..6e26469 --- /dev/null +++ b/python/Cargo.lock @@ -0,0 +1,326 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "aho-corasick" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "autocfg" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "ctor" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "ghost" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "indoc" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "indoc-impl 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-hack 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "indoc-impl" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro-hack 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", + "unindent 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "inventory" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ctor 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "ghost 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "inventory-impl 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "inventory-impl" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "itoa" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "libc" +version = "0.2.66" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "memchr" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "num-traits" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "paste" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "paste-impl 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-hack 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "paste-impl" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro-hack 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "proc-macro-hack" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "proc-macro2" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "pyo3" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "indoc 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "inventory 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", + "paste 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "pyo3cls 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)", + "spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "unindent 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "version_check 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "pyo3-derive-backend" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "pyo3cls" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "pyo3-derive-backend 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "quote" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "raptorq" +version = "1.0.0" +dependencies = [ + "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "raptorq-py" +version = "0.1.0" +dependencies = [ + "pyo3 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)", + "raptorq 1.0.0", +] + +[[package]] +name = "regex" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", + "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "regex-syntax" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "ryu" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "serde" +version = "1.0.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "serde_derive" +version = "1.0.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "serde_json" +version = "1.0.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", + "ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "syn" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "thread_local" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "unicode-xid" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "unindent" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "version_check" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[metadata] +"checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d" +"checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" +"checksum ctor 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "cd8ce37ad4184ab2ce004c33bf6379185d3b1c95801cab51026bd271bf68eedc" +"checksum ghost 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2a36606a68532b5640dc86bb1f33c64b45c4682aad4c50f3937b317ea387f3d6" +"checksum indoc 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3f9553c1e16c114b8b77ebeb329e5f2876eed62a8d51178c8bc6bff0d65f98f8" +"checksum indoc-impl 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b714fc08d0961716390977cdff1536234415ac37b509e34e5a983def8340fb75" +"checksum inventory 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f4cece20baea71d9f3435e7bbe9adf4765f091c5fe404975f844006964a71299" +"checksum inventory-impl 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c2869bf972e998977b1cb87e60df70341d48e48dca0823f534feb91ea44adaf9" +"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" +"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +"checksum libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)" = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558" +"checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e" +"checksum num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c81ffc11c212fa327657cb19dd85eb7419e163b5b076bede2bdb5c974c07e4" +"checksum paste 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "423a519e1c6e828f1e73b720f9d9ed2fa643dce8a7737fb43235ce0b41eeaa49" +"checksum paste-impl 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "4214c9e912ef61bf42b81ba9a47e8aad1b2ffaf739ab162bf96d1e011f54e6c5" +"checksum proc-macro-hack 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)" = "ecd45702f76d6d3c75a80564378ae228a85f0b59d2f3ed43c91b4a69eb2ebfc5" +"checksum proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9c9e470a8dc4aeae2dee2f335e8f533e2d4b347e1434e5671afc49b054592f27" +"checksum pyo3 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7f9df1468dddf8a59ec799cf3b930bb75ec09deabe875ba953e06c51d1077136" +"checksum pyo3-derive-backend 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)" = "9f6e56fb3e97b344a8f87d036f94578399402c6b75949de6270cd07928f790b1" +"checksum pyo3cls 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)" = "97452dcdf5941627ebc5c06664a07821fc7fc88d7515f02178193a8ebe316468" +"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" +"checksum regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dc220bd33bdce8f093101afe22a037b8eb0e5af33592e6a9caafff0d4cb81cbd" +"checksum regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "11a7e20d1cce64ef2fed88b66d347f88bd9babb82845b2b858f3edbf59a4f716" +"checksum ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8" +"checksum serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "414115f25f818d7dfccec8ee535d76949ae78584fc4f79a6f45a904bf8ab4449" +"checksum serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "128f9e303a5a29922045a830221b8f78ec74a5f544944f3d5984f8ec3895ef64" +"checksum serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)" = "48c575e0cc52bdd09b47f330f646cf59afc586e9c4e3ccd6fc1f625b8ea1dad7" +"checksum spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" +"checksum syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)" = "dff0acdb207ae2fe6d5976617f887eb1e35a2ba52c13c7234c790960cdad9238" +"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" +"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" +"checksum unindent 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "63f18aa3b0e35fed5a0048f029558b1518095ffe2a0a31fb87c93dece93a4993" +"checksum version_check 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "078775d0255232fb988e6fccf26ddc9d1ac274299aaedcedce21c6f72cc533ce" diff --git a/python/Cargo.toml b/python/Cargo.toml new file mode 100644 index 0000000..e8ed851 --- /dev/null +++ b/python/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "raptorq-py" +description = "RaptorQ (RFC6330)" +license = "Apache-2.0" +repository = "https://github.com/cberner/raptorq" +version = "0.1.0" +authors = ["Felix Schorer "] +edition = "2018" + +[lib] +name = "raptorq" +crate-type = ["cdylib"] + +[dependencies.raptorq] +path = "../" +version = "1.0.0" + +[dependencies.pyo3] +version = "0.8.4" +features = ["extension-module"] \ No newline at end of file diff --git a/python/Makefile b/python/Makefile new file mode 100644 index 0000000..33a2bee --- /dev/null +++ b/python/Makefile @@ -0,0 +1,15 @@ +build: + maturin build + +release: + maturin build --release + +install: + maturin develop + +lint: + cargo lichking check + cargo fmt --all -- --check + +test: install + python3 -m unittest discover \ No newline at end of file diff --git a/python/README.md b/python/README.md new file mode 100644 index 0000000..3ce3917 --- /dev/null +++ b/python/README.md @@ -0,0 +1,19 @@ +The Python bindings are generated using [pyo3](https://github.com/PyO3/pyo3). +Rust 1.37.0-nightly or higher is required for building [pyo3](https://github.com/PyO3/pyo3) projects. +``` +$ rustup install nightly +$ rustup override set nightly +``` + +Some operating systems require additional packages to be installed. +``` +$ sudo apt install python3-dev +``` + +[maturin](https://github.com/PyO3/maturin) is recommended for building this crate. +``` +$ pip install maturin +$ maturin build +``` + +Alternatively, refer to the [Building and Distribution section](https://pyo3.rs/v0.8.5/building_and_distribution.html) in the [pyo3 user guide](https://pyo3.rs/v0.8.5/). \ No newline at end of file diff --git a/python/pyproject.toml b/python/pyproject.toml new file mode 100644 index 0000000..548b353 --- /dev/null +++ b/python/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["maturin"] +build-backend = "maturin" \ No newline at end of file diff --git a/python/src/lib.rs b/python/src/lib.rs new file mode 100644 index 0000000..2421746 --- /dev/null +++ b/python/src/lib.rs @@ -0,0 +1,74 @@ +use pyo3::prelude::*; +use pyo3::types::*; +use raptorq::{ + Decoder as DecoderNative, Encoder as EncoderNative, EncodingPacket, + ObjectTransmissionInformation, +}; + +#[pyclass] +struct Encoder { + encoder: EncoderNative, +} + +#[pymethods] +impl Encoder { + #[staticmethod] + pub fn with_defaults(data: &PyBytes, maximum_transmission_unit: u16) -> PyResult { + let encoder = EncoderNative::with_defaults(data.as_bytes(), maximum_transmission_unit); + Ok(Encoder { encoder }) + } + + pub fn get_encoded_packets<'p>( + &self, + py: Python<'p>, + repair_packets_per_block: u32, + ) -> PyResult> { + let packets: Vec<&PyBytes> = self + .encoder + .get_encoded_packets(repair_packets_per_block) + .iter() + .map(|packet| PyBytes::new(py, &packet.serialize())) + .collect(); + + Ok(packets) + } +} + +#[pyclass] +struct Decoder { + decoder: DecoderNative, +} + +#[pymethods] +impl Decoder { + #[staticmethod] + pub fn with_defaults( + transfer_length: u64, + maximum_transmission_unit: u16, + ) -> PyResult { + let config = ObjectTransmissionInformation::with_defaults( + transfer_length, + maximum_transmission_unit, + ); + let decoder = DecoderNative::new(config); + Ok(Decoder { decoder }) + } + + pub fn decode<'p>( + &mut self, + py: Python<'p>, + packet: &PyBytes, + ) -> PyResult> { + let result = self + .decoder + .decode(EncodingPacket::deserialize(packet.as_bytes())); + Ok(result.map(|data| PyBytes::new(py, &data))) + } +} + +#[pymodule] +fn raptorq(_py: Python, m: &PyModule) -> PyResult<()> { + m.add_class::()?; + m.add_class::()?; + Ok(()) +} diff --git a/python/test/__init__.py b/python/test/__init__.py new file mode 100644 index 0000000..a16ae05 --- /dev/null +++ b/python/test/__init__.py @@ -0,0 +1,35 @@ +import os +import random +from unittest import TestCase + + +class EncoderDecoderTestCase(TestCase): + def test_encoder(self): + from raptorq import Encoder + + data = os.urandom(1024) + encoder = Encoder.with_defaults(data, 512) + packets = encoder.get_encoded_packets(42) + + self.assertIsInstance(packets, list) + self.assertGreater(len(packets), 0) + for packet in packets: + self.assertIsInstance(packet, bytes) + + def test_decoder(self): + from raptorq import Encoder, Decoder + + data = os.urandom(1024) + encoder = Encoder.with_defaults(data, 512) + packets = encoder.get_encoded_packets(42) + + random.shuffle(packets) + + decoded_data = None + decoder = Decoder.with_defaults(len(data), 512) + for packet in packets: + decoded_data = decoder.decode(packet) + if decoded_data is not None: + break + + self.assertEqual(decoded_data, data)