Skip to content

Commit 0a6d6cd

Browse files
author
Guillaume Fraux
committed
Add a trait to abstract the actual storage of data
This allow to use the same Python class for both owned particles and particles in a system or a molecule.
1 parent b8c940b commit 0a6d6cd

File tree

3 files changed

+82
-28
lines changed

3 files changed

+82
-28
lines changed

src/lib.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@ extern crate lumol;
66

77
#[macro_use]
88
mod macros;
9-
mod systems;
109
mod error;
10+
mod traits;
11+
12+
mod systems;
1113

1214
py_module_initializer!(lumol, initlumol, PyInit_lumol, |py, m| {
1315
try!(m.add(py, "__doc__", "Modern and extensible molecular simulation engine"));

src/systems/particle.rs

Lines changed: 63 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,79 @@
11
use cpython::{PyObject, PyErr, PyResult, PyTuple, ToPyObject, PythonObject};
2-
use lumol;
3-
use lumol::types::Vector3D;
42
use std::cell::RefCell;
3+
use lumol;
4+
5+
use traits::Callback;
56

67
register!(|py, m| {
78
try!(m.add_class::<Particle>(py));
89
Ok(())
910
});
1011

1112
py_class!(class Particle |py| {
12-
data particle: RefCell<lumol::sys::Particle>;
13+
data particle: Box<Callback<lumol::sys::Particle>>;
1314
def __new__(_cls, name: &str) -> PyResult<Particle> {
14-
Particle::create_instance(py, RefCell::new(lumol::sys::Particle::new(name)))
15+
Particle::create_instance(py,
16+
Box::new(RefCell::new(lumol::sys::Particle::new(name)))
17+
)
1518
}
1619

1720
def name(&self) -> PyResult<String> {
18-
Ok(self.particle(py).borrow().name().into())
21+
let mut name = String::new();
22+
self.particle(py).with_ref(&mut |atom| {
23+
name += atom.name();
24+
});
25+
Ok(name)
1926
}
2027

2128
def set_name(&self, name: &str) -> PyResult<PyObject> {
22-
self.particle(py).borrow_mut().set_name(name);
29+
self.particle(py).with_mut(&mut |atom| {
30+
atom.set_name(name)
31+
});
2332
Ok(py.None())
2433
}
2534

2635
def mass(&self) -> PyResult<f64> {
27-
Ok(self.particle(py).borrow().mass)
36+
let mut mass = 0.0;
37+
self.particle(py).with_ref(&mut |atom| {
38+
mass = atom.mass;
39+
});
40+
Ok(mass)
2841
}
2942

3043
def set_mass(&self, mass: f64) -> PyResult<PyObject> {
31-
self.particle(py).borrow_mut().mass = mass;
44+
self.particle(py).with_mut(&mut |atom| {
45+
atom.mass = mass;
46+
});
3247
Ok(py.None())
3348
}
3449

3550
def charge(&self) -> PyResult<f64> {
36-
Ok(self.particle(py).borrow().charge)
51+
let mut charge = 0.0;
52+
self.particle(py).with_ref(&mut |atom| {
53+
charge = atom.charge;
54+
});
55+
Ok(charge)
3756
}
3857

3958
def set_charge(&self, charge: f64) -> PyResult<PyObject> {
40-
self.particle(py).borrow_mut().charge = charge;
59+
self.particle(py).with_mut(&mut |atom| {
60+
atom.charge = charge;
61+
});
4162
Ok(py.None())
4263
}
4364

4465
def position(&self) -> PyResult<PyTuple> {
45-
let position = &self.particle(py).borrow().position;
46-
47-
let x = position[0].to_py_object(py).into_object();
48-
let y = position[1].to_py_object(py).into_object();
49-
let z = position[2].to_py_object(py).into_object();
50-
51-
Ok(PyTuple::new(py, &[x, y, z]))
66+
let mut position = [0.0; 3];
67+
self.particle(py).with_ref(&mut |atom| {
68+
position[0] = atom.position[0];
69+
position[1] = atom.position[1];
70+
position[2] = atom.position[2];
71+
});
72+
Ok(PyTuple::new(py, &[
73+
position[0].to_py_object(py).into_object(),
74+
position[1].to_py_object(py).into_object(),
75+
position[2].to_py_object(py).into_object(),
76+
]))
5277
}
5378

5479
def set_position(&self, position: &PyTuple) -> PyResult<PyObject> {
@@ -69,19 +94,26 @@ py_class!(class Particle |py| {
6994
raise!(py, "Position elements should be numbers"))
7095
);
7196

72-
self.particle(py).borrow_mut().position = Vector3D::new(x, y, z);
73-
97+
self.particle(py).with_mut(&mut |atom| {
98+
atom.position[0] = x;
99+
atom.position[1] = y;
100+
atom.position[2] = z;
101+
});
74102
Ok(py.None())
75103
}
76104

77105
def velocity(&self) -> PyResult<PyTuple> {
78-
let velocity = &self.particle(py).borrow().velocity;
79-
80-
let x = velocity[0].to_py_object(py).into_object();
81-
let y = velocity[1].to_py_object(py).into_object();
82-
let z = velocity[2].to_py_object(py).into_object();
83-
84-
Ok(PyTuple::new(py, &[x, y, z]))
106+
let mut velocity = [0.0; 3];
107+
self.particle(py).with_ref(&mut |atom| {
108+
velocity[0] = atom.velocity[0];
109+
velocity[1] = atom.velocity[1];
110+
velocity[2] = atom.velocity[2];
111+
});
112+
Ok(PyTuple::new(py, &[
113+
velocity[0].to_py_object(py).into_object(),
114+
velocity[1].to_py_object(py).into_object(),
115+
velocity[2].to_py_object(py).into_object(),
116+
]))
85117
}
86118

87119
def set_velocity(&self, velocity: &PyTuple) -> PyResult<PyObject> {
@@ -102,7 +134,11 @@ py_class!(class Particle |py| {
102134
raise!(py, "Velocity elements should be numbers"))
103135
);
104136

105-
self.particle(py).borrow_mut().velocity = Vector3D::new(x, y, z);
137+
self.particle(py).with_mut(&mut |atom| {
138+
atom.velocity[0] = x;
139+
atom.velocity[1] = y;
140+
atom.velocity[2] = z;
141+
});
106142

107143
Ok(py.None())
108144
}

src/traits.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
use std::cell::RefCell;
2+
3+
pub trait Callback<T>: Send {
4+
fn with_ref(&self, function: &mut FnMut(&T));
5+
fn with_mut(&self, function: &mut FnMut(&mut T));
6+
}
7+
8+
impl<T: Send> Callback<T> for RefCell<T> {
9+
fn with_ref(&self, function: &mut FnMut(&T)) {
10+
function(&*self.borrow())
11+
}
12+
13+
fn with_mut(&self, function: &mut FnMut(&mut T)) {
14+
function(&mut *self.borrow_mut())
15+
}
16+
}

0 commit comments

Comments
 (0)