rustmex_core/
pointers.rs

1/*!
2 * Module defining how Matlab pointers behave
3 */
4
5use std::ops::{Deref, DerefMut, Drop};
6use std::clone::Clone;
7use std::borrow::{ToOwned, Borrow};
8use std::convert::AsRef;
9use std::ptr::NonNull;
10
11use crate::{mxArray, MatlabClass};
12
13use crate::shim::{
14	rustmex_duplicate_array,
15	rustmex_destroy_array,
16};
17
18/**
19 * A Matlab Pointer is a marker trait, used to be generic over pointers which can be used
20 * across API boundaries with Matlab. Two of these are already implemented (Matlab
21 * returns an opaque pointer to objects, so these can just be used as-is as references),
22 * which leaves the third — the owned type — to be implemented. _See_ [`MxArray`].
23 */
24pub trait MatlabPtr: Deref<Target = mxArray> {
25
26	/**
27	 * A [`MatlabPtr`] is an untyped pointer; it does not know what the type of the
28	 * data it holds is. However, Rustmex provides types which represent that
29	 * information. If the `MatlabPtr` holds one of those data types, "upcast" the
30	 * pointer to that type and return it.
31	 */
32	// TODO: Rewrite so that it doesn't eat the mxArray, especially not when its an
33	// owned pointer
34	fn is_a<W>(self) -> Result<W, crate::convert::FromMatlabError<Self>> where
35		W: MatlabClass<Self>,
36		Self: Sized,
37	{
38		W::from_mx_array(self)
39	}
40}
41
42impl<'a> MatlabPtr for &'a mut mxArray { }
43impl<'a> MatlabPtr for &'a mxArray { }
44impl MatlabPtr for MxArray {}
45
46pub trait MutMatlabPtr: DerefMut<Target = mxArray> + MatlabPtr {}
47impl<T> MutMatlabPtr for T where T: DerefMut<Target = mxArray> + MatlabPtr {}
48
49/**
50 * The owned variant of an mxArray. Some of Matlab's mex functions specify that the
51 * caller is responsible for deallocating the object when it is done with it, unless the
52 * object in question is returned to Matlab. This cannot be expressed with just (mutable)
53 * references, so this type implements the owned type.
54 *
55 * It is basically a wrapper around a mutable reference to an mxArray, but it implements
56 * the drop trait, so when it is dropped it calls `mxDestroyArray`. It implements
57 * [`Deref`] and [`DerefMut`], so it can also be used where-ever a (mutable) reference to
58 * an mxArray is expected.
59 */
60#[repr(transparent)]
61#[derive(Debug)]
62pub struct MxArray(NonNull<mxArray>);
63
64impl Drop for MxArray {
65	fn drop(&mut self) {
66		unsafe { rustmex_destroy_array(self.0.as_mut()) };
67	}
68}
69
70impl Deref for MxArray {
71	type Target = mxArray;
72
73	fn deref(&self) -> &Self::Target {
74		unsafe { self.0.as_ref() }
75	}
76}
77
78impl DerefMut for MxArray {
79	fn deref_mut(&mut self) -> &mut Self::Target {
80		unsafe { self.0.as_mut() }
81	}
82}
83
84impl mxArray {
85	/**
86	 * Create a deep copy of the array, and return as an owned type. However,
87	 * consider using [`MatlabClass::duplicate`] instead if you are already working
88	 * with [`MatlabClass`]es.
89	 */
90	pub fn duplicate(&self) -> MxArray {
91		let ptr = unsafe { rustmex_duplicate_array(self) };
92		if ptr.is_null() {
93			panic!("OOM");
94		}
95		unsafe { MxArray::assume_responsibility(&mut *ptr ) }
96	}
97}
98
99impl Clone for MxArray {
100	fn clone(&self) -> Self {
101		self.duplicate()
102	}
103}
104
105impl Borrow<mxArray> for MxArray {
106	fn borrow(&self) -> &mxArray {
107		self.deref()
108	}
109}
110
111impl ToOwned for mxArray {
112	type Owned = MxArray;
113
114	fn to_owned(&self) -> Self::Owned {
115		self.duplicate()
116	}
117}
118
119impl AsRef<mxArray> for mxArray {
120	fn as_ref(&self) -> &mxArray {
121		self
122	}
123}
124
125impl AsRef<mxArray> for MxArray {
126	fn as_ref(&self) -> &mxArray {
127		self.deref()
128	}
129
130}
131
132impl MxArray {
133	// NOTE: I'm not yet sure whether accepting and returning references from the
134	// responsibility handling methods is the best idea. Maybe accepting/returning
135	// (NonNull) pointers is better?
136
137	/**
138	 * Create an MxArray by assuming responsibility for freeing an mxArray. Unless
139	 * you have allocated an mxArray yourself, you do not need this.
140	 */
141	pub unsafe fn assume_responsibility(mx: &'static mut mxArray) -> Self {
142		Self(NonNull::new_unchecked(mx as *mut mxArray))
143	}
144
145	/// _See_ [`MxArray::assume_responsibility`].
146	pub unsafe fn assume_responsibility_ptr(mx: *mut mxArray) -> Self {
147		Self(NonNull::new(mx).expect("Non-null pointer"))
148	}
149
150	/**
151	 * Transfer responsibility for deallocating this mxArray back to Matlab. Unless
152	 * you are manually calling raw matlab functions, you do not need this.
153	 */
154	pub unsafe fn transfer_responsibility(o: Self) -> &'static mut mxArray {
155		&mut *Self::transfer_responsibility_ptr(o)
156	}
157
158	/// _See_ [`MxArray::transfer_responsibility`].
159	pub unsafe fn transfer_responsibility_ptr(o: Self) -> *mut mxArray {
160		let ptr = o.0.as_ptr();
161		std::mem::forget(o);
162		ptr
163	}
164}