Skip to content

Commit dc99521

Browse files
committed
test 2
1 parent fbde1a0 commit dc99521

File tree

5 files changed

+96
-52
lines changed

5 files changed

+96
-52
lines changed

.github/workflows/rust.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,5 +69,5 @@ jobs:
6969
shell: bash
7070
- run: rustup target add ${{ matrix.target }}
7171
- run: cargo build --verbose
72-
- run: cargo test tests --verbose
72+
# - run: cargo test tests --verbose
7373
- run: cargo run --example basic

src/cvode.rs

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@
1616
use std::{
1717
borrow::Borrow,
1818
ffi::{c_int, c_void, c_long},
19-
marker::PhantomData, ptr,
19+
marker::PhantomData,
20+
ptr,
2021
};
2122
use sundials_sys::*;
2223
use super::{
@@ -231,7 +232,8 @@ where
231232
cvode_mem.0,
232233
Some(Self::cvrhs),
233234
self.t0,
234-
y0 as *mut _) };
235+
V::as_ptr(&y0)) // `CVodeInit` does not modify `y0`.
236+
};
235237
if r == CV_MEM_FAIL {
236238
let msg = "a memory allocation request has failed";
237239
return Err(Error::Failure{name: self.name, msg})
@@ -248,7 +250,7 @@ where
248250
let linsolver = unsafe { LinSolver::spgmr(
249251
self.name,
250252
ctx.as_ptr(),
251-
y0 as *mut _)? };
253+
V::as_ptr(&y0))? };
252254
let r = unsafe { CVodeSetLinearSolver(
253255
cvode_mem.0, linsolver.as_ptr(), ptr::null_mut()) };
254256
if r != CVLS_SUCCESS as i32 {
@@ -290,14 +292,14 @@ where
290292
let n_roots = self.cb.n_roots;
291293
if n_roots > 0 {
292294
let r = unsafe {
293-
CVodeRootInit(cvode_mem.0, M as _,
295+
CVodeRootInit(cvode_mem.0, n_roots as _,
294296
Some(Self::cvroot1)) };
295297
if r == CV_MEM_FAIL {
296298
panic!("Sundials::cvode::CVode::root: memory allocation \
297299
failed.");
298300
}
299-
rootsfound = Vec::with_capacity(M);
300-
rootsfound.resize(M, 0);
301+
rootsfound = Vec::with_capacity(n_roots);
302+
rootsfound.resize(n_roots, 0);
301303
} else {
302304
rootsfound = vec![];
303305
}
@@ -352,13 +354,16 @@ where
352354
}
353355
}
354356

355-
// Implement the Drop trait only on the pointer to be able to move
356-
// values out of the structure `CVode`.
357+
// `cvode` depends on the context, so store it alongside.
357358
#[derive(Debug)]
358359
struct CVodeMem(*mut c_void);
359360

361+
// Implement the Drop trait only on the pointer to be able to move
362+
// values out of the structure `CVode`.
360363
impl Drop for CVodeMem {
361-
fn drop(&mut self) { unsafe { CVodeFree(&mut self.0) } }
364+
fn drop(&mut self) {
365+
unsafe { CVodeFree(&mut self.0) }
366+
}
362367
}
363368

364369
impl CVodeMem {
@@ -417,7 +422,7 @@ where V: Vector,
417422
// We hold `Matrix` and `LinSolver` so they are freed when `CVode`
418423
// is dropped.
419424
_matrix: Option<Matrix>,
420-
_linsolver: Option<LinSolver>,
425+
_linsolver: Option<LinSolver>, // depends on `ctx`
421426
rootsfound: Vec<c_int>, // cache, with len() == number of eq
422427
cb: CB,
423428
cvode_mem: CVodeMem, // depends on `ctx`.
@@ -546,7 +551,7 @@ where
546551
// Reinitialize to allow any time `t`, even if not monotonic
547552
// w.r.t. previous calls.
548553
let ret = unsafe {
549-
CVodeReInit(self.cvode_mem.0, t0, y0 as *mut _)
554+
CVodeReInit(self.cvode_mem.0, t0, V::as_ptr(&y0))
550555
};
551556
if ret != CV_SUCCESS {
552557
panic!("CVodeReInit returned code {ret}. Please report.");
@@ -584,7 +589,7 @@ where Ctx: Context,
584589
// Safety: `yout` does not escape this function and so will
585590
// not outlive `self.ctx` and `y` will not move while `yout`
586591
// is in use.
587-
let yout =
592+
let mut yout =
588593
match unsafe { V::as_mut_nvector(y, self.ctx.as_ptr()) }{
589594
Some(yout) => yout,
590595
None => panic!("The context of the output vector y is not \
@@ -594,7 +599,7 @@ where Ctx: Context,
594599
let r = unsafe { CVode(
595600
self.cvode_mem.0,
596601
t,
597-
yout,
602+
V::as_mut_ptr(&mut yout),
598603
&mut tret, itask) };
599604
let status = match r {
600605
CV_SUCCESS => CVStatus::Ok,

src/linear_solver/mod.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ pub struct LinSolver(SUNLinearSolver);
88
impl Drop for LinSolver {
99
// FIXME: handle possible returned error?
1010
// https://sundials.readthedocs.io/en/latest/sunlinsol/SUNLinSol_API_link.html?highlight=SUNLinSolFree#c.SUNLinSolFree
11-
fn drop(&mut self) { unsafe { SUNLinSolFree(self.0); } }
11+
fn drop(&mut self) {
12+
unsafe { SUNLinSolFree(self.0); }
13+
}
1214
}
1315

1416
impl LinSolver {

src/matrix/mod.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,11 @@ use super::{Context, Error};
66
pub struct Matrix(SUNMatrix);
77

88
impl Drop for Matrix {
9-
fn drop(&mut self) { unsafe { SUNMatDestroy(self.0) } }
9+
fn drop(&mut self) {
10+
println!("drop(Matrix)");
11+
unsafe { SUNMatDestroy(self.0) }
12+
println!("drop(Matrix) done");
13+
}
1014
}
1115

1216
impl Matrix {

src/vector/mod.rs

Lines changed: 69 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,17 @@ pub unsafe trait Vector: Clone {
4242
/// otherwise.
4343
///
4444
/// # Safety
45-
/// The return value must not outlive `v` and `ctx`. Moreover `v`
45+
/// The return value must not outlive `v` and `ctx`. The C code
46+
/// should *not* modify the returned N_Vector. Moreover `v`
4647
/// should not move while the return value is in use.
47-
unsafe fn as_nvector(
48-
v: &Self, ctx: SUNContext) -> Option<*const _generic_N_Vector>;
48+
unsafe fn as_nvector(v: &Self, ctx: SUNContext) -> Option<Self::NVec>;
49+
50+
/// Alias of read only `N_Vector`, or wrapper around `N_Vector` if,
51+
/// for example, allocation (and a custom [`Drop`]) is needed.
52+
type NVec;
53+
54+
/// Return a raw pointer [`N_Vector`] which must *not* be modified.
55+
fn as_ptr(nv: &Self::NVec) -> N_Vector;
4956

5057
/// Return a wrapper of a `N_Vector` that can mutate `self`. If
5158
/// `self` already possesses a [`Context`][crate::Context], this
@@ -56,7 +63,14 @@ pub unsafe trait Vector: Clone {
5663
/// The return value must not outlive `v` and `ctx`. Moreover `v`
5764
/// should not move while the return value is in use.
5865
unsafe fn as_mut_nvector(
59-
v: &mut Self, ctx: SUNContext) -> Option<N_Vector>;
66+
v: &mut Self, ctx: SUNContext) -> Option<Self::NVecMut>;
67+
68+
/// Alias of `N_Vector`, or wrapper around `N_Vector` if
69+
/// allocation (and a custom [`Drop`]) is needed.
70+
type NVecMut;
71+
72+
/// Return a raw pointer [`N_Vector`].
73+
fn as_mut_ptr(nv: &mut Self::NVecMut) -> N_Vector;
6074
}
6175

6276

@@ -243,23 +257,27 @@ impl<T: NVectorOps> Ops for T {
243257
// Rust memory cannot be uninitialized, thus clone.
244258
let v = w.clone();
245259
//// Sundials functions — slow.
246-
// let nv = N_VNewEmpty((*nw).sunctx);
260+
let nv = N_VNewEmpty((*nw).sunctx);
247261
// if N_VCopyOps(nw, nv) != 0 {
248262
// return std::ptr::null_mut()
249263
// }
250-
// (*nv).content = Box::into_raw(Box::new(v)) as *mut c_void;
251-
// nv
252-
253-
//// libc version — safe as Sundials uses malloc.
254-
let sunctx = (*nw).sunctx;
255-
let nv = libc::malloc(
256-
std::mem::size_of::<_generic_N_Vector>()) as N_Vector;
257-
(*nv).sunctx = sunctx;
258-
let n = std::mem::size_of::<_generic_N_Vector_Ops>();
259-
let ops = libc::malloc(n);
260-
libc::memcpy(ops, (*nw).ops as *mut c_void, n);
261-
(*nv).ops = ops as N_Vector_Ops;
264+
libc::memcpy(
265+
(*nv).ops as *mut c_void,
266+
(*nw).ops as *mut c_void,
267+
std::mem::size_of::<_generic_N_Vector_Ops>());
262268
(*nv).content = Box::into_raw(Box::new(v)) as *mut c_void;
269+
270+
//// libc version — slightly faster and should be safe as
271+
//// Sundials uses malloc makes `N_VFreeEmpty` hang on Windows.
272+
// let sunctx = (*nw).sunctx;
273+
// let nv = libc::malloc(
274+
// std::mem::size_of::<_generic_N_Vector>()) as N_Vector;
275+
// (*nv).sunctx = sunctx;
276+
// let n = std::mem::size_of::<_generic_N_Vector_Ops>();
277+
// let ops = libc::malloc(n);
278+
// libc::memcpy(ops, (*nw).ops as *mut c_void, n);
279+
// (*nv).ops = ops as N_Vector_Ops;
280+
// (*nv).content = Box::into_raw(Box::new(v)) as *mut c_void;
263281
nv
264282
}
265283

@@ -630,15 +648,14 @@ impl<T: NVectorOps> Ops for T {
630648
};
631649
}
632650

633-
#[inline]
634-
unsafe fn new_nvector<T: NVectorOps + Ops>(ctx: SUNContext) -> N_Vector {
635-
let nv = N_VNewEmpty(ctx);
636-
if nv.is_null() {
637-
panic!("sundials::vector::new_nvector: \
638-
Could not allocate new N_Vector.");
639-
}
640-
(*nv).ops = Box::into_raw(Box::new(T::OPS));
641-
nv
651+
/// Wrapper around a read-only `N_Vector`.
652+
pub struct SharedVec {
653+
nvector: _generic_N_Vector, // This is allocated and freed by Rust.
654+
}
655+
656+
/// Wrapper around a `N_Vector` to de-allocate the structure when dropped.
657+
pub struct SharedVecMut {
658+
nvector: _generic_N_Vector,
642659
}
643660

644661
unsafe impl<T: NVectorOps> Vector for T {
@@ -656,23 +673,39 @@ unsafe impl<T: NVectorOps> Vector for T {
656673
}
657674
}
658675

676+
type NVec = SharedVec;
677+
678+
fn as_ptr(nv: &Self::NVec) -> N_Vector {
679+
&nv.nvector as *const _ as *mut _
680+
}
681+
682+
type NVecMut = SharedVecMut;
683+
684+
fn as_mut_ptr(nv: &mut Self::NVecMut) -> N_Vector {
685+
&mut nv.nvector
686+
}
687+
659688
#[inline]
660-
unsafe fn as_nvector(
661-
v: &Self, ctx: SUNContext
662-
) -> Option<*const _generic_N_Vector> {
689+
unsafe fn as_nvector(v: &Self, ctx: SUNContext) -> Option<Self::NVec> {
663690
// See https://sundials.readthedocs.io/en/latest/nvectors/NVector_API_link.html#implementing-a-custom-nvector
664-
let nv = new_nvector::<T>(ctx);
665-
(*nv).content = v as *const T as *mut c_void;
666-
Some(nv)
691+
let nvector = _generic_N_Vector {
692+
content: v as *const T as *mut c_void,
693+
ops: Box::into_raw(Box::new(T::OPS)),
694+
sunctx: ctx,
695+
};
696+
Some(SharedVec { nvector })
667697
}
668698

669699
#[inline]
670700
unsafe fn as_mut_nvector(
671701
v: &mut Self, ctx: SUNContext
672-
) -> Option<N_Vector> {
673-
let nv = new_nvector::<T>(ctx);
674-
(*nv).content = v as *mut T as *mut c_void;
675-
Some(nv)
702+
) -> Option<Self::NVecMut> {
703+
let nvector = _generic_N_Vector {
704+
content: v as *const T as *mut c_void,
705+
ops: Box::into_raw(Box::new(T::OPS)),
706+
sunctx: ctx,
707+
};
708+
Some(SharedVecMut { nvector })
676709
}
677710
}
678711

0 commit comments

Comments
 (0)