#[cfg(feature = "python")]
use pyo3::exceptions::PyValueError;
#[cfg(feature = "python")]
use pyo3::prelude::*;
#[cfg(feature = "python")]
use pyo3::types::PyBytes;
#[cfg(feature = "python")]
#[pyclass(name = "Client")]
pub struct PyClient {
_placeholder: u8,
}
#[cfg(feature = "python")]
#[pymethods]
impl PyClient {
#[new]
#[pyo3(signature = (config_path=None))]
fn new(config_path: Option<&str>) -> PyResult<Self> {
let _ = config_path;
Ok(PyClient { _placeholder: 0 })
}
fn add(&self, data: &[u8]) -> PyResult<String> {
if data.is_empty() {
return Err(PyValueError::new_err("Data cannot be empty"));
}
let mock_cid = format!("bafkreidummy{:016x}", data.len());
Ok(mock_cid)
}
fn get<'py>(&self, py: Python<'py>, cid: &str) -> PyResult<Bound<'py, PyBytes>> {
if cid.is_empty() {
return Err(PyValueError::new_err("CID cannot be empty"));
}
let mock_data = format!("Data for CID: {}", cid);
Ok(PyBytes::new(py, mock_data.as_bytes()))
}
fn has(&self, cid: &str) -> PyResult<bool> {
if cid.is_empty() {
return Err(PyValueError::new_err("CID cannot be empty"));
}
Ok(true)
}
fn version(&self) -> String {
"ipfrs-interface 0.1.0".to_string()
}
fn __enter__(slf: Py<Self>) -> Py<Self> {
slf
}
fn __exit__(
&mut self,
_exc_type: Option<&Bound<'_, PyAny>>,
_exc_value: Option<&Bound<'_, PyAny>>,
_traceback: Option<&Bound<'_, PyAny>>,
) -> PyResult<bool> {
Ok(false) }
fn __repr__(&self) -> String {
"Client()".to_string()
}
fn __str__(&self) -> String {
"IPFRS Client".to_string()
}
}
#[cfg(feature = "python")]
#[pyclass(name = "BlockInfo")]
pub struct PyBlockInfo {
#[pyo3(get)]
pub cid: String,
#[pyo3(get)]
pub size: usize,
}
#[cfg(feature = "python")]
#[pymethods]
impl PyBlockInfo {
#[new]
fn new(cid: String, size: usize) -> Self {
PyBlockInfo { cid, size }
}
fn __repr__(&self) -> String {
format!("BlockInfo(cid='{}', size={})", self.cid, self.size)
}
}
#[cfg(feature = "python")]
#[pymodule]
fn ipfrs(m: &Bound<'_, PyModule>) -> PyResult<()> {
m.add_class::<PyClient>()?;
m.add_class::<PyBlockInfo>()?;
m.add("__version__", "0.1.0")?;
m.add("__author__", "IPFRS Team")?;
Ok(())
}
#[cfg(all(test, feature = "python"))]
mod tests {
use super::*;
#[test]
fn test_client_creation() {
Python::attach(|_py| {
let client = PyClient::new(None).unwrap();
assert_eq!(client.version(), "ipfrs-interface 0.1.0");
});
}
#[test]
fn test_add_and_get() {
Python::attach(|py| {
let client = PyClient::new(None).unwrap();
let data = b"Hello, IPFRS!";
let cid = client.add(data).unwrap();
assert!(cid.starts_with("bafkreidummy"));
let retrieved = client.get(py, &cid).unwrap();
let bytes = retrieved.as_bytes();
assert!(bytes.len() > 0);
});
}
#[test]
fn test_has() {
Python::attach(|_py| {
let client = PyClient::new(None).unwrap();
let exists = client.has("bafkreitest123").unwrap();
assert!(exists);
});
}
#[test]
fn test_empty_data() {
Python::attach(|_py| {
let client = PyClient::new(None).unwrap();
let result = client.add(&[]);
assert!(result.is_err());
});
}
#[test]
fn test_empty_cid() {
Python::attach(|py| {
let client = PyClient::new(None).unwrap();
let result = client.get(py, "");
assert!(result.is_err());
let result = client.has("");
assert!(result.is_err());
});
}
}
#[cfg(not(feature = "python"))]
pub struct PyClient;
#[cfg(not(feature = "python"))]
impl PyClient {
pub fn new(_config_path: Option<&str>) -> Result<Self, &'static str> {
Err("Python bindings not enabled. Build with --features python")
}
}