Skip to content

Commit

Permalink
-
Browse files Browse the repository at this point in the history
  • Loading branch information
A.Shpak committed May 10, 2024
1 parent 6de7469 commit 3ca3751
Show file tree
Hide file tree
Showing 6 changed files with 49 additions and 29 deletions.
4 changes: 4 additions & 0 deletions epyxid.pyi
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from datetime import datetime

__version__: str


class XID:
"""
Expand Down Expand Up @@ -40,6 +42,8 @@ class XID:
Extract the incrementing counter.
"""

def __hash__(self) -> int: ...

def __bytes__(self) -> bytes: ...

def __str__(self) -> str: ...
Expand Down
10 changes: 8 additions & 2 deletions justfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,14 @@

build:
maturin build \
--interpreter python3.8
--find-interpreter

venv:
source venv/bin/activate

tests:
maturin develop
pytest -v test_xid.py
set -e
python3.8 -m pip install epyxid --find-links dist --force-reinstall
python3.8 -m pip install pytest
python3.8 -m pytest -v test_xid.py
12 changes: 6 additions & 6 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
use std::str::FromStr;

use pyo3::prelude::{pymodule, PyModule, PyResult, Python};
use pyo3::wrap_pyfunction;
use pyo3::prelude::{pymodule, wrap_pyfunction, Bound, PyModule, PyResult, Python};

use crate::errors::XIDError;
use crate::utils::{xid_create, xid_from_bytes, xid_from_str};
use crate::wrapper::XID;

const PY_MODULE_VERSION: &str = "1.0.5";

mod errors;
mod utils;
mod wrapper;

#[pymodule]
fn epyxid(_py: Python, m: &PyModule) -> PyResult<()> {
fn epyxid(py: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> {
m.add_class::<XID>()?;
m.add_function(wrap_pyfunction!(xid_create, m)?)?;
m.add_function(wrap_pyfunction!(xid_from_str, m)?)?;
m.add_function(wrap_pyfunction!(xid_from_bytes, m)?)?;
m.add("XIDError", _py.get_type::<XIDError>())?;
m.add("XIDError", py.get_type_bound::<XIDError>())?;
m.add("__version__", PY_MODULE_VERSION)?;
Ok(())
}
11 changes: 6 additions & 5 deletions src/utils.rs
Original file line number Diff line number Diff line change
@@ -1,29 +1,30 @@
use std::str::FromStr;

use pyo3::prelude::PyBytesMethods;
use pyo3::types::PyBytes;
use pyo3::{pyfunction, PyResult};
use pyo3::{pyfunction, Bound, PyResult};
use xid::{Id, ParseIdError};

use crate::errors::XIDError;
use crate::wrapper::XID;

#[pyfunction]
pub fn xid_create() -> PyResult<XID> {
Ok(XID { inner: xid::new() })
Ok(XID(xid::new()))
}

#[pyfunction]
pub fn xid_from_str(s: &str) -> PyResult<XID> {
match Id::from_str(s) {
Ok(id) => Ok(XID { inner: id }),
Ok(id) => Ok(XID(id)),
Err(error) => Err(XIDError::new_err(error.to_string())),
}
}

#[pyfunction]
pub fn xid_from_bytes(b: &PyBytes) -> PyResult<XID> {
pub fn xid_from_bytes(b: Bound<PyBytes>) -> PyResult<XID> {
match id_from_bytes(b.as_bytes()) {
Ok(value) => Ok(XID { inner: value }),
Ok(value) => Ok(XID(value)),
Err(error) => Err(XIDError::new_err(error.to_string())),
}
}
Expand Down
36 changes: 20 additions & 16 deletions src/wrapper.rs
Original file line number Diff line number Diff line change
@@ -1,47 +1,45 @@
use std::str::FromStr;
use std::hash::{DefaultHasher, Hash, Hasher};

use pyo3::types::{PyBytes, PyDateTime};
use pyo3::{pyclass, pymethods, PyResult, Python};
use pyo3::{pyclass, pymethods, Bound, PyResult, Python};
use xid::Id;

#[pyclass]
pub struct XID {
pub inner: Id,
}
pub struct XID(pub Id);

#[pymethods]
impl XID {
fn as_bytes<'p>(&self, _py: Python<'p>) -> &'p PyBytes {
PyBytes::new(_py, self.inner.as_bytes())
fn as_bytes<'p>(&self, _py: Python<'p>) -> Bound<'p, PyBytes> {
PyBytes::new_bound(_py, self.0.as_bytes())
}

fn to_str(&self) -> String {
self.inner.to_string()
self.0.to_string()
}

#[getter]
fn machine<'p>(&self, _py: Python<'p>) -> &'p PyBytes {
PyBytes::new(_py, &self.inner.machine())
fn machine<'p>(&self, _py: Python<'p>) -> Bound<'p, PyBytes> {
PyBytes::new_bound(_py, &self.0.machine())
}

#[getter]
fn pid(&self) -> u16 {
self.inner.pid()
self.0.pid()
}

#[getter]
fn time<'p>(&self, _py: Python<'p>) -> PyResult<&'p PyDateTime> {
let raw = self.inner.as_bytes();
fn time<'p>(&self, _py: Python<'p>) -> PyResult<Bound<'p, PyDateTime>> {
let raw = self.0.as_bytes();
let unix_ts = u32::from_be_bytes([raw[0], raw[1], raw[2], raw[3]]);
PyDateTime::from_timestamp(_py, unix_ts as f64, None)
PyDateTime::from_timestamp_bound(_py, unix_ts as f64, None)
}

#[getter]
fn counter(&self) -> u32 {
self.inner.counter()
self.0.counter()
}

fn __bytes__<'p>(&self, _py: Python<'p>) -> &'p PyBytes {
fn __bytes__<'p>(&self, _py: Python<'p>) -> Bound<'p, PyBytes> {
self.as_bytes(_py)
}

Expand Down Expand Up @@ -76,4 +74,10 @@ impl XID {
fn __ge__(&self, object: &XID) -> bool {
self.to_str() >= object.to_str()
}

fn __hash__(&self) -> u64 {
let mut hasher = DefaultHasher::new();
self.0.hash(&mut hasher);
hasher.finish()
}
}
5 changes: 5 additions & 0 deletions test_xid.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ def test_from_bytes_valid() -> None:
assert str(xid) == XID_STR


def test_hash() -> None:
xid = xid_from_bytes(XID_BYTES)
assert isinstance(hash(xid), int)


def test_from_bytes_invalid_length() -> None:
with raises(ValueError):
xid_from_bytes(bytes([0x4d, 0x88, 0xe1, 0x5b, 0x60, 0xf4, 0x86, 0xe4, 0x28, 0x41, 0x2d]))

0 comments on commit 3ca3751

Please sign in to comment.