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
2 changes: 2 additions & 0 deletions changelog.d/70.clean.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Remove now unused helper functions for converting `Vector` values to/from native Python `lists`<ISSUES_LIST>.
For more details, see [neo4j-python-driver#1263](https://github.com/neo4j/neo4j-python-driver/pull/1263).
68 changes: 52 additions & 16 deletions src/vector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,29 +13,65 @@
// See the License for the specific language governing permissions and
// limitations under the License.

mod native_conversion;
mod swap_endian;
use pyo3::exceptions::PyValueError;
use pyo3::prelude::*;
use pyo3::types::{PyBytes, PyInt};
use pyo3::{pyfunction, Bound, PyErr, PyResult};

use crate::register_package;
use pyo3::prelude::*;

#[pyfunction]
fn swap_endian<'py>(
type_size: Bound<'py, PyInt>,
data: Bound<'py, PyBytes>,
) -> PyResult<Bound<'py, PyBytes>> {
let py = type_size.py();

let type_size: usize = match type_size.extract::<usize>() {
Ok(type_size @ 2) | Ok(type_size @ 4) | Ok(type_size @ 8) => type_size,
_ => {
return Err(PyErr::new::<PyValueError, _>(format!(
"Unsupported type size {type_size}",
)))
}
};
let bytes = &data.as_bytes();
let len = bytes.len();
if len % type_size != 0 {
return Err(PyErr::new::<PyValueError, _>(
"Data length not a multiple of type_size",
Copy link
Contributor

@RichardIrons-neo4j RichardIrons-neo4j Nov 7, 2025

Choose a reason for hiding this comment

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

Could add the bad length and size to the message here?

Copy link
Member Author

@robsdedude robsdedude Nov 7, 2025

Choose a reason for hiding this comment

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

Could do. But this is really just a second line of defense. The driver code calling this already preforms this check.

Import here: https://github.com/neo4j/neo4j-python-driver/blob/d10d2cd689340d9f2acfe67ca19131936e722f04/src/neo4j/vector.py#L45-L48

Assignment here: https://github.com/neo4j/neo4j-python-driver/blob/d10d2cd689340d9f2acfe67ca19131936e722f04/src/neo4j/vector.py#L618-L623

Check followed by call here: https://github.com/neo4j/neo4j-python-driver/blob/d10d2cd689340d9f2acfe67ca19131936e722f04/src/neo4j/vector.py#L581-L585

So I think it's not worth bothering. I also remove it and let if fall through to the assert_eq!(src.len() % N, 0); in swap_n resulting in an uglier error message. But again, only when messing up in the driver code would this ever surface. 🤷 I really don't have strong opinion on this.

));
}

PyBytes::new_with(py, bytes.len(), |out| {
match type_size {
2 => swap_n::<2>(bytes, out),
4 => swap_n::<4>(bytes, out),
8 => swap_n::<8>(bytes, out),
_ => unreachable!(),
}
Ok(())
})
}

#[inline(always)]
fn swap_n<const N: usize>(src: &[u8], dst: &mut [u8]) {
// Doesn't technically need to be a function with a const generic, but this
// allows the compiler to optimize the code better.
assert_eq!(src.len(), dst.len());
assert_eq!(src.len() % N, 0);
for i in (0..src.len()).step_by(N) {
for j in 0..N {
dst[i + j] = src[i + N - j - 1];
}
}
}

pub(super) fn init_module(m: &Bound<PyModule>, name: &str) -> PyResult<()> {
m.gil_used(false)?;
register_package(m, name)?;

m.add_function(wrap_pyfunction!(swap_endian::swap_endian, m)?)?;
m.add_function(wrap_pyfunction!(native_conversion::vec_f64_from_native, m)?)?;
m.add_function(wrap_pyfunction!(native_conversion::vec_f64_to_native, m)?)?;
m.add_function(wrap_pyfunction!(native_conversion::vec_f32_from_native, m)?)?;
m.add_function(wrap_pyfunction!(native_conversion::vec_f32_to_native, m)?)?;
m.add_function(wrap_pyfunction!(native_conversion::vec_i64_from_native, m)?)?;
m.add_function(wrap_pyfunction!(native_conversion::vec_i64_to_native, m)?)?;
m.add_function(wrap_pyfunction!(native_conversion::vec_i32_from_native, m)?)?;
m.add_function(wrap_pyfunction!(native_conversion::vec_i32_to_native, m)?)?;
m.add_function(wrap_pyfunction!(native_conversion::vec_i16_from_native, m)?)?;
m.add_function(wrap_pyfunction!(native_conversion::vec_i16_to_native, m)?)?;
m.add_function(wrap_pyfunction!(native_conversion::vec_i8_from_native, m)?)?;
m.add_function(wrap_pyfunction!(native_conversion::vec_i8_to_native, m)?)?;
m.add_function(wrap_pyfunction!(swap_endian, m)?)?;

Ok(())
}
Loading