Wrap Rust Library for Python (without changing Rust library)

Do you mind me asking how? Taking Vector3 as an example.

Original Library:

// vector3.rs
pub struct Vector3 {
    pub x: i32,
    pub y: i32,
    pub z: i32
}

impl Vector3 {
    pub fn new(x: i32, y: i32, z: i32) -> Vector3 {
        Vector3 { x, y, z }
    }
    pub fn length(&self) -> f64 {
        ((self.x*self.x + self.y*self.y + self.z*self.z) as f64).sqrt()
    }
    pub fn add(&self, other: &Vector3) -> Vector3 {
        Vector3 { x: self.x + other.x, y: self.y + other.y, z: self.z + other.z }
    }
}

Bindings:

// py_vector3.rs
use pyo3::prelude::*;
use crate::vector3;

#[pyclass]
pub struct Vector3 {
    pub obj: vector3::Vector3
}

#[pymethods]
impl Vector3 {
    #[new]
    pub fn new(x: i32, y: i32, z: i32) -> Vector3 {
        Vector3{ obj: vector3::Vector3{ x, y, z } }
    }
    pub fn length(&self) -> f64 {
        self.obj.length()
    }
    pub fn add(&self, other: &Vector3) -> Vector3 {
        Vector3{ obj: self.obj.add(&other.obj) }
    }
    pub fn x(&self) -> i32 {
        self.obj.x
    }
    pub fn y(&self) -> i32 {
        self.obj.y
    }
    pub fn z(&self) -> i32 {
        self.obj.z
    }
}
#[pymodule]
fn my_rust(_py: Python, m: &PyModule) -> PyResult<()> {
    m.add_class::<Vector3>()?;
    Ok(())
}

Now, Python's Vector3 holds an instance of Rust's vector3::Vector3. This seems ok, but when we get to defining the functions, it's quite a big amount of boilerplate (almost re-implementing all the original functions). This is very different to the C++ pybind approach, where we don't have to create any dummy structs and don't need to implement any functions (we simply point to the original ones). Is something similar possible with PyO3?