@@ -42,10 +42,17 @@ pub unsafe trait Vector: Clone {
42
42
/// otherwise.
43
43
///
44
44
/// # 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`
46
47
/// 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 ;
49
56
50
57
/// Return a wrapper of a `N_Vector` that can mutate `self`. If
51
58
/// `self` already possesses a [`Context`][crate::Context], this
@@ -56,7 +63,14 @@ pub unsafe trait Vector: Clone {
56
63
/// The return value must not outlive `v` and `ctx`. Moreover `v`
57
64
/// should not move while the return value is in use.
58
65
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 ;
60
74
}
61
75
62
76
@@ -243,23 +257,27 @@ impl<T: NVectorOps> Ops for T {
243
257
// Rust memory cannot be uninitialized, thus clone.
244
258
let v = w. clone ( ) ;
245
259
//// Sundials functions — slow.
246
- // let nv = N_VNewEmpty((*nw).sunctx);
260
+ let nv = N_VNewEmpty ( ( * nw) . sunctx ) ;
247
261
// if N_VCopyOps(nw, nv) != 0 {
248
262
// return std::ptr::null_mut()
249
263
// }
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 > ( ) ) ;
262
268
( * 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;
263
281
nv
264
282
}
265
283
@@ -630,15 +648,14 @@ impl<T: NVectorOps> Ops for T {
630
648
} ;
631
649
}
632
650
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 ,
642
659
}
643
660
644
661
unsafe impl < T : NVectorOps > Vector for T {
@@ -656,23 +673,39 @@ unsafe impl<T: NVectorOps> Vector for T {
656
673
}
657
674
}
658
675
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
+
659
688
#[ 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 > {
663
690
// 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 } )
667
697
}
668
698
669
699
#[ inline]
670
700
unsafe fn as_mut_nvector (
671
701
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 } )
676
709
}
677
710
}
678
711
0 commit comments