1use super::*;
2#[repr(transparent)]
4pub struct AnyTensorRef {
5 __marker: PhantomData<[u8]>,
6}
7
8impl AnyTensorRef {
9 pub(crate) fn as_ptr(&self) -> *mut mnn_sys::Tensor {
11 self as *const Self as *mut mnn_sys::Tensor
12 }
13
14 pub(crate) unsafe fn from_ptr<'s>(tensor: *mut mnn_sys::Tensor) -> &'s Self {
15 unsafe { &*tensor.cast() }
16 }
17
18 pub(crate) unsafe fn from_mut_ptr<'s>(tensor: *mut mnn_sys::Tensor) -> &'s mut Self {
19 unsafe { &mut *tensor.cast() }
20 }
21
22 pub fn device_id(&self) -> u64 {
24 unsafe { mnn_sys::Tensor_deviceId(self.as_ptr()) }
25 }
26
27 pub fn shape(&self) -> TensorShape {
29 unsafe { mnn_sys::Tensor_shape(self.as_ptr()) }.into()
30 }
31
32 #[doc(alias = "dims")]
34 pub fn dimensions(&self) -> usize {
35 unsafe { mnn_sys::Tensor_dimensions(self.as_ptr()) as usize }
36 }
37
38 pub fn width(&self) -> u32 {
40 unsafe { mnn_sys::Tensor_width(self.as_ptr()) as u32 }
41 }
42
43 pub fn height(&self) -> u32 {
45 unsafe { mnn_sys::Tensor_height(self.as_ptr()) as u32 }
46 }
47
48 pub fn channel(&self) -> u32 {
50 unsafe { mnn_sys::Tensor_channel(self.as_ptr()) as u32 }
51 }
52
53 pub fn batch(&self) -> u32 {
55 unsafe { mnn_sys::Tensor_batch(self.as_ptr()) as u32 }
56 }
57
58 pub fn size(&self) -> usize {
63 unsafe { mnn_sys::Tensor_usize(self.as_ptr()) }
64 }
65
66 pub fn element_size(&self) -> usize {
71 unsafe { mnn_sys::Tensor_elementSize(self.as_ptr()) as usize }
72 }
73
74 pub fn get_type(&self) -> mnn_sys::halide_type_t {
76 unsafe { mnn_sys::Tensor_getType(self.as_ptr()) }
77 }
78
79 pub fn is_type_of<Ha: HalideType>(&self) -> bool {
81 let htc = mnn_sys::halide_type_of::<Ha>();
82 unsafe { mnn_sys::Tensor_isTypeOf(self.as_ptr(), htc) }
83 }
84
85 pub fn is_same_type(&self, other: &AnyTensorRef) -> bool {
87 unsafe { mnn_sys::Tensor_isTypeOf(self.as_ptr(), other.get_type()) }
88 }
89
90 pub fn get_dimension_type(&self) -> DimensionType {
92 debug_assert!(!self.as_ptr().is_null());
93 From::from(unsafe { mnn_sys::Tensor_getDimensionType(self.as_ptr()) })
94 }
95
96 pub fn is_dynamic_unsized(&self) -> bool {
98 self.shape().as_ref().contains(&-1)
99 }
100
101 fn ensure_compatible(&self, other: &AnyTensorRef) -> Result<()> {
106 crate::ensure!(
107 self.is_same_type(other),
108 ErrorKind::TensorError;
109 format!(
110 "Tensor element types do not match: {:?} vs {:?}",
111 self.get_type(),
112 other.get_type()
113 )
114 );
115 crate::ensure!(
116 self.shape().as_ref() == other.shape().as_ref(),
117 ErrorKind::SizeMismatch {
118 expected: self.element_size(),
119 got: other.element_size()
120 };
121 format!(
122 "Tensor shapes do not match: {:?} vs {:?}",
123 self.shape(),
124 other.shape()
125 )
126 );
127 Ok(())
128 }
129
130 pub fn copy_from_host_tensor(&mut self, tensor: &AnyTensorRef) -> Result<()> {
132 self.ensure_compatible(tensor)?;
133 let ret = unsafe { mnn_sys::Tensor_copyFromHostTensor(self.as_ptr(), tensor.as_ptr()) };
134 crate::ensure!(ret != 0, ErrorKind::TensorCopyFailed(ret));
135 Ok(())
136 }
137
138 pub fn copy_to_host_tensor(&self, tensor: &mut AnyTensorRef) -> Result<()> {
140 self.ensure_compatible(tensor)?;
141 let ret = unsafe { mnn_sys::Tensor_copyToHostTensor(self.as_ptr(), tensor.as_ptr()) };
142 crate::ensure!(ret != 0, ErrorKind::TensorCopyFailed(ret));
143 Ok(())
144 }
145
146 pub fn create_host_tensor_from_device<T: HalideType + Copy>(
152 &self,
153 copy_data: bool,
154 ) -> Tensor<Owned<T>, Host> {
155 assert!(
156 self.is_type_of::<T>(),
157 "Tensor element type does not match {}",
158 core::any::type_name::<T>()
159 );
160 let shape = self.shape();
161 assert!(
162 !self.is_dynamic_unsized(),
163 "Cannot create a host tensor from a device tensor with a dynamic shape {shape:?}; resize the session first"
164 );
165 let dm_type = self.get_dimension_type();
166 let mut out = Tensor::new(shape, dm_type);
167
168 if copy_data {
169 self.copy_to_host_tensor(unsafe { out.as_any_tensor_mut() })
170 .expect("Failed to copy data from device tensor");
171 }
172 out
173 }
174
175 pub fn wait(this: &Self, map_type: MapType, finish: bool) {
177 unsafe {
178 mnn_sys::Tensor_wait(this.as_ptr(), map_type, finish as i32);
179 }
180 }
181}
182
183#[cfg(test)]
184mod tests {
185 use super::*;
186
187 #[test]
188 fn copy_rejects_element_type_mismatch() {
189 let src = TensorOwned::<f32, Host>::from_shape_data(
190 [1, 2, 3],
191 DimensionType::Caffe,
192 &[1., 2., 3., 4., 5., 6.],
193 );
194 let mut dst = TensorOwned::<u8, Host>::new([1, 2, 3], DimensionType::Caffe);
195 let err = unsafe {
196 src.as_any_tensor()
197 .copy_to_host_tensor(dst.as_any_tensor_mut())
198 }
199 .expect_err("copying f32 into u8 must fail");
200 assert!(format!("{err}").contains("element types do not match"));
201 let err = unsafe {
202 dst.as_any_tensor_mut()
203 .copy_from_host_tensor(src.as_any_tensor())
204 }
205 .expect_err("copying f32 into u8 must fail");
206 assert!(format!("{err}").contains("element types do not match"));
207 }
208
209 #[test]
210 fn copy_rejects_shape_mismatch() {
211 let src = TensorOwned::<f32, Host>::new([1, 2, 3], DimensionType::Caffe);
212 let mut dst = TensorOwned::<f32, Host>::new([1, 3, 2], DimensionType::Caffe);
213 let err = unsafe {
214 src.as_any_tensor()
215 .copy_to_host_tensor(dst.as_any_tensor_mut())
216 }
217 .expect_err("mismatched shapes must fail");
218 assert!(format!("{err}").contains("shapes do not match"));
219 }
220}