Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 12 additions & 5 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Rust
name: CI

on:
push:
Expand All @@ -10,13 +10,20 @@ env:
CARGO_TERM_COLOR: always

jobs:
build:

pre-commit:
name: Pre-commit checks
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- uses: pre-commit/action@v3.0.1

test:
name: Tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build
run: cargo build --verbose
- name: Run tests
run: cargo test --verbose
4 changes: 2 additions & 2 deletions .gitlab-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ stages:

build:
stage: build
image:
image:
name: ghcr.io/pyo3/maturin:latest
entrypoint: [""]
environment:
Expand All @@ -42,7 +42,7 @@ build:
publish:
stage: publish
needs: ["build"]
image:
image:
name: ghcr.io/pyo3/maturin:main
entrypoint: [""]
variables:
Expand Down
37 changes: 37 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v6.0.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-toml
- id: check-merge-conflict

- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.15.1
hooks:
- id: ruff-check
- id: ruff-format

- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.19.1
hooks:
- id: mypy
args: [--config-file, pyreccaster/pyproject.toml]
files: ^pyreccaster/python/

- repo: local
hooks:
- id: cargo-fmt
name: cargo fmt
language: system
entry: cargo fmt --all -- --check
pass_filenames: false
types: [rust]
- id: cargo-clippy
name: cargo clippy
language: system
entry: cargo clippy --workspace --all-targets
pass_filenames: false
types: [rust]
6 changes: 6 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,9 @@
members = [ "examples/*", "pyreccaster","reccaster", "wire"]
default-members = ["pyreccaster", "reccaster", "wire"]
resolver = "2"

[workspace.lints.rust]
missing_docs = "deny"

[workspace.lints.clippy]
all = { level = "deny", priority = -1 }
16 changes: 8 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# Recsync-rs

A rust implementation of [recsync](https://github.com/ChannelFinder/recsync) protocl with python bindings.Aiming for bug to bug compatibility with current implementation of RecCeiver.
A rust implementation of [recsync](https://github.com/ChannelFinder/recsync) protocl with python bindings.Aiming for bug to bug compatibility with current implementation of RecCeiver.
See the [recsync](https://github.com/ChannelFinder/recsync) original repository for details about the protocol and theory of operation.

## Project status
The project initially would implement only **ReCaster** in Rust with Python binding to be used along with [p4p](https://github.com/mdavidsaver/p4p).
**RecCeiver** is not implemented yet. Recsync-rs is split into different sections. First part is `wire` which implements only the protocol definition, encoders and decoders.
It used by **ReCaster** and **RecCeiver** (not implemented yet). Second part is `reccaster` which is **ReCaster** implementation, as it will be used as rust library.
## Project status
The project initially would implement only **ReCaster** in Rust with Python binding to be used along with [p4p](https://github.com/mdavidsaver/p4p).
**RecCeiver** is not implemented yet. Recsync-rs is split into different sections. First part is `wire` which implements only the protocol definition, encoders and decoders.
It used by **ReCaster** and **RecCeiver** (not implemented yet). Second part is `reccaster` which is **ReCaster** implementation, as it will be used as rust library.
Finally, `pyreccaster` is a [pyo3](https://github.com/PyO3/pyo3) Rust-wrapped Python library of `reccaster`.

### RecCaster functionality
Expand All @@ -17,7 +17,7 @@ Finally, `pyreccaster` is a [pyo3](https://github.com/PyO3/pyo3) Rust-wrapped Py
* [X] Add Info
* [ ] Delete Record

## Usage Example
## Usage Example

Using Rust
```rust
Expand Down Expand Up @@ -78,7 +78,7 @@ if __name__ == "__main__":
## Requirements
* Rust 1.54.0 or later
* Python 3.7 or later
* [Maturin](https://github.com/PyO3/maturin)
* [Maturin](https://github.com/PyO3/maturin)

## Build and Installation

Expand All @@ -99,7 +99,7 @@ pip install maturin
cd pyreccaster
maturin build
# to install the python bindings
pip install .
pip install .
```

### Cross-Compile Python bindings for Windows
Expand Down
3 changes: 3 additions & 0 deletions examples/basic-reccaster/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ name = "basic-reccaster"
version = "0.1.0"
edition = "2021"

[lints]
workspace = true

[dependencies]
tokio = { version = "1", features = ["full"] }
tracing = "^0.1.41"
Expand Down
15 changes: 9 additions & 6 deletions examples/basic-reccaster/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,23 @@
// You must comply with both licenses to use, modify, or distribute this software.
// See the LICENSE file for details.

use std::collections::HashMap;
use tracing_subscriber;
#![allow(missing_docs)]
use reccaster::{record::Record, Reccaster};
use std::collections::HashMap;

#[tokio::main]
async fn main() {

tracing_subscriber::fmt().with_max_level(tracing::Level::DEBUG).init();
tracing_subscriber::fmt()
.with_max_level(tracing::Level::DEBUG)
.init();

let mut record = Record::new("DEV:RECASTER:RUST".to_string(), "ai".to_string());
record.properties.insert("recordDesc".to_string(), "Rust Recaster".to_string());
record
.properties
.insert("recordDesc".to_string(), "Rust Recaster".to_string());
let records: Vec<Record> = vec![record];

let mut props: HashMap<String, String> = HashMap::new();
let mut props: HashMap<String, String> = HashMap::new();
props.insert("ENGINEER".into(), "Rust Recaster".into());
props.insert("HOSTNAME".into(), "Example-Host-Machine".into());

Expand Down
4 changes: 4 additions & 0 deletions pyreccaster/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ authors = ["Aqeel AlShafei <aqeel.alshafei@stfc.ac.uk>"]
license = "MIT AND BSD-3-Clause"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[lints]
workspace = true

[lib]
name = "pyreccaster"
crate-type = ["cdylib"]
Expand Down
16 changes: 16 additions & 0 deletions pyreccaster/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,26 @@ classifiers = [
tests = [
"pytest",
]
lint = [
"ruff",
"mypy",
]
dynamic = ["version"]

[tool.maturin]
profile = "release"
python-source = "python"
compatibility = "linux"
features = ["pyo3/extension-module"]

[tool.ruff]
target-version = "py38"
src = ["python"]
exclude = ["test.py"]

[tool.ruff.lint]
select = ["E", "F", "I", "UP", "B", "RUF"]
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure about adding UP (pyupgrde) option here


[tool.mypy]
strict = true
ignore_missing_imports = true
4 changes: 2 additions & 2 deletions pyreccaster/python/pyreccaster/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from .pyreccaster import *

from . import pyreccaster
from .pyreccaster import * # noqa: F403

__doc__ = pyreccaster.__doc__
if hasattr(pyreccaster, "__all__"):
Expand Down
5 changes: 2 additions & 3 deletions pyreccaster/python/tests/test_all.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import pytest
import pyreccaster


def test_sum_as_string():
assert pyreccaster.sum_as_string(1, 1) == "2"
def test_sum_as_string() -> None:
assert pyreccaster.sum_as_string(1, 1) == "2" # type: ignore[attr-defined]
48 changes: 37 additions & 11 deletions pyreccaster/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,33 @@
// You must comply with both licenses to use, modify, or distribute this software.
// See the LICENSE file for details.

#![allow(missing_docs)]
use std::{collections::HashMap, sync::Arc};

use pyo3::prelude::*;
use pyo3_async_runtimes::tokio::future_into_py_with_locals;
use reccaster::{Record, Reccaster};
use reccaster::{Reccaster, Record};
use tokio::sync::Mutex;

#[pyclass]
pub struct PyRecord(Record);

#[pymethods]
impl PyRecord {
#[new]
#[pyo3(signature = (name, r#type, alias=None, properties=HashMap::new()))]
fn new(name: String, r#type: String, alias: Option<String>, properties: HashMap<String, String>) -> Self {
PyRecord(Record { name, r#type, alias, properties })
fn new(
name: String,
r#type: String,
alias: Option<String>,
properties: HashMap<String, String>,
) -> Self {
PyRecord(Record {
name,
r#type,
alias,
properties,
})
}

#[getter]
Expand All @@ -42,16 +53,23 @@ impl PyRecord {
fn properties(&self) -> PyResult<HashMap<String, String>> {
Ok(self.0.properties.clone())
}

}

impl FromPyObject<'_> for PyRecord {
fn extract_bound(ob: &Bound<'_, PyAny>) -> PyResult<Self> {
let name: String = ob.getattr("name")?.extract().unwrap_or_else(|_| "OPS no name !!!!!!!!!!!".to_string());
let name: String = ob
.getattr("name")?
.extract()
.unwrap_or_else(|_| "OPS no name !!!!!!!!!!!".to_string());
let r#type: String = ob.getattr("type")?.extract()?;
let alias: Option<String> = ob.getattr("alias")?.extract()?;
let properties: HashMap<String, String> = ob.getattr("properties")?.extract()?;
Ok(PyRecord (Record { name, r#type, alias, properties }))
Ok(PyRecord(Record {
name,
r#type,
alias,
properties,
}))
}
}

Expand All @@ -62,14 +80,22 @@ struct PyReccaster {

#[pymethods]
impl PyReccaster {

#[staticmethod]
fn setup(py: Python, records: Vec<PyRecord>, props: Option<HashMap<String, String>>) -> PyResult<Bound<'_, pyo3::PyAny>> {
fn setup(
py: Python<'_>,
records: Vec<PyRecord>,
props: Option<HashMap<String, String>>,
) -> PyResult<Bound<'_, pyo3::PyAny>> {
let locals = pyo3_async_runtimes::tokio::get_current_locals(py)?;
let pvs = records.iter().map(|record: &PyRecord| record.0.clone()).collect::<Vec<Record>>();
let pvs = records
.iter()
.map(|record: &PyRecord| record.0.clone())
.collect::<Vec<Record>>();
future_into_py_with_locals(py, locals, async move {
let recc = Reccaster::new(pvs, props).await;
let pyrecc = PyReccaster { reccaster: Arc::new(Mutex::new(recc)) };
let pyrecc = PyReccaster {
reccaster: Arc::new(Mutex::new(recc)),
};
Python::with_gil(|_py| Ok(pyrecc))
})
}
Expand Down
3 changes: 3 additions & 0 deletions reccaster/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ license = "MIT AND BSD-3-Clause"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[lints]
workspace = true

[dependencies]
tokio = { version = "^1.36", features = ["full"] }
tokio-util = { version = "^0.7.11", features = ["full"] }
Expand Down
Loading