objc2-core-ml 0.3.2

Bindings to the CoreML framework
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
//! This file has been automatically generated by `objc2`'s `header-translator`.
//! DO NOT EDIT
use core::ffi::*;
use core::ptr::NonNull;
use objc2::__framework_prelude::*;
#[cfg(feature = "objc2-core-video")]
use objc2_core_video::*;
use objc2_foundation::*;

use crate::*;

/// The data type of scalars in the multi-array.
///
/// See also [Apple's documentation](https://developer.apple.com/documentation/coreml/mlmultiarraydatatype?language=objc)
// NS_ENUM
#[repr(transparent)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct MLMultiArrayDataType(pub NSInteger);
impl MLMultiArrayDataType {
    #[doc(alias = "MLMultiArrayDataTypeDouble")]
    pub const Double: Self = Self(0x10000 | 64);
    #[doc(alias = "MLMultiArrayDataTypeFloat64")]
    pub const Float64: Self = Self(0x10000 | 64);
    #[doc(alias = "MLMultiArrayDataTypeFloat32")]
    pub const Float32: Self = Self(0x10000 | 32);
    #[doc(alias = "MLMultiArrayDataTypeFloat16")]
    pub const Float16: Self = Self(0x10000 | 16);
    #[doc(alias = "MLMultiArrayDataTypeFloat")]
    pub const Float: Self = Self(0x10000 | 32);
    #[doc(alias = "MLMultiArrayDataTypeInt32")]
    pub const Int32: Self = Self(0x20000 | 32);
    #[doc(alias = "MLMultiArrayDataTypeInt8")]
    pub const Int8: Self = Self(0x20000 | 8);
}

unsafe impl Encode for MLMultiArrayDataType {
    const ENCODING: Encoding = NSInteger::ENCODING;
}

unsafe impl RefEncode for MLMultiArrayDataType {
    const ENCODING_REF: Encoding = Encoding::Pointer(&Self::ENCODING);
}

extern_class!(
    /// Use `MLMultiArray` to store a multi-dimensional value.
    ///
    /// Unlike `MLShapedArray` or `MLTensor`, `MLMultiArray` can be used in Obj-C code. Unlike `MLTensor`, `MLMultiArray` is
    /// always backed by a concrete storage.
    ///
    /// The object has properties to define the interpretation of the storage.
    ///
    /// `.dataType` defines the interpretation of raw bytes into a numeric scalar value. For example,
    /// `MLMultiArrayDataTypeFloat32` means the backing storage uses IEEE 754 Float32 encoding.
    ///
    /// `.shape` defines the multi-dimensional space. For example, 30 x 20 image with three color components (Red, Green,
    /// Blue) could be defined using the shape `[3, 20, 30]`.
    ///
    /// `.strides` defines the offset addressing of the scalar for a given coordinates. For example, the image above might
    /// use `[640, 32, 1]` as the `strides`. Then, the scalar at (1, 10, 15) is stored at `640 * 1 + 32 * 10 + 1 * 15`, or
    /// 975th scalar in the storage. In general, the scalar offset for coordinates `index` and strides `strides` is:
    ///
    /// ```text
    /// scalarOffset = sum_d index[d]*strides[d]
    /// ```
    ///
    /// The backing storage can be a heap allocated buffer or CVPixelBuffer. Though CVPixelBuffer backing supports limited
    /// data types, `MLModel` could share the storage with backend hardware such as Apple Neural Engine without copy.
    ///
    /// See also [Apple's documentation](https://developer.apple.com/documentation/coreml/mlmultiarray?language=objc)
    #[unsafe(super(NSObject))]
    #[derive(Debug, PartialEq, Eq, Hash)]
    pub struct MLMultiArray;
);

extern_conformance!(
    unsafe impl NSCoding for MLMultiArray {}
);

extern_conformance!(
    unsafe impl NSObjectProtocol for MLMultiArray {}
);

extern_conformance!(
    unsafe impl NSSecureCoding for MLMultiArray {}
);

impl MLMultiArray {
    extern_methods!(
        /// Unsafe pointer to underlying buffer holding the data
        #[deprecated = "Use getBytesWithHandler or getMutableBytesWithHandler instead. For Swift, use withUnsafeBytes or withUnsafeMutableBytes."]
        #[unsafe(method(dataPointer))]
        #[unsafe(method_family = none)]
        pub unsafe fn dataPointer(&self) -> NonNull<c_void>;

        /// Scalar's data type.
        #[unsafe(method(dataType))]
        #[unsafe(method_family = none)]
        pub unsafe fn dataType(&self) -> MLMultiArrayDataType;

        /// Shape of the multi-dimensional space that this instance represents.
        #[unsafe(method(shape))]
        #[unsafe(method_family = none)]
        pub unsafe fn shape(&self) -> Retained<NSArray<NSNumber>>;

        /// Strides.
        ///
        /// It defines the offset of the scalar of a given coordinate index in the storage, which is:
        /// ```text
        /// scalarOffset = sum_d index[d]*strides[d]
        /// ```
        #[unsafe(method(strides))]
        #[unsafe(method_family = none)]
        pub unsafe fn strides(&self) -> Retained<NSArray<NSNumber>>;

        /// Count of total number of addressable scalars.
        ///
        /// The value is same as `product_d shape[d]`.
        #[unsafe(method(count))]
        #[unsafe(method_family = none)]
        pub unsafe fn count(&self) -> NSInteger;

        #[cfg(feature = "objc2-core-video")]
        /// Returns the backing pixel buffer if exists, otherwise nil.
        #[unsafe(method(pixelBuffer))]
        #[unsafe(method_family = none)]
        pub unsafe fn pixelBuffer(&self) -> Option<Retained<CVPixelBuffer>>;
    );
}

/// Methods declared on superclass `NSObject`.
impl MLMultiArray {
    extern_methods!(
        #[unsafe(method(init))]
        #[unsafe(method_family = init)]
        pub unsafe fn init(this: Allocated<Self>) -> Retained<Self>;

        #[unsafe(method(new))]
        #[unsafe(method_family = new)]
        pub unsafe fn new() -> Retained<Self>;
    );
}

/// Creation.
impl MLMultiArray {
    extern_methods!(
        /// Creates the object.
        ///
        /// The contents of the object are left uninitialized; the client must initialize it.
        ///
        /// The scalars will use the first-major contiguous layout.
        ///
        /// - Parameters:
        /// - shape: The shape
        /// - dataType: The data type
        /// - error: Filled with error information on error.
        #[unsafe(method(initWithShape:dataType:error:_))]
        #[unsafe(method_family = init)]
        pub unsafe fn initWithShape_dataType_error(
            this: Allocated<Self>,
            shape: &NSArray<NSNumber>,
            data_type: MLMultiArrayDataType,
        ) -> Result<Retained<Self>, Retained<NSError>>;

        /// Creates the object with specified strides.
        ///
        /// The contents of the object are left uninitialized; the client must initialize it.
        ///
        /// ```swift
        /// let shape = [2, 3];
        /// let strides = [4, 1]
        ///
        /// let multiArray = MLMultiArray(shape: shape, dataType: .float32, strides: strides)
        /// XCTAssertEqual(multiArray.shape, shape as [NSNumber])
        /// XCTAssertEqual(multiArray.strides, strides as [NSNumber])
        /// ```
        ///
        /// ```objc
        /// NSArray
        /// <NSNumber
        /// *> *shape =
        /// @
        /// [
        /// @
        /// 2,
        /// @
        /// 3];
        /// NSArray
        /// <NSNumber
        /// *> *strides =
        /// @
        /// [
        /// @
        /// 4,
        /// @
        /// 1];
        ///
        /// MLMultiArray *multiArray = [[MLMultiArray alloc] initWithShape:shape
        /// dataType:MLMultiArrayDataTypeFloat32
        /// strides:strides];
        /// XCTAssertEqualObjects(multiArray.shape, shape);
        /// XCTAssertEqualObjects(multiArray.strides, strides);
        /// ```
        ///
        /// - Parameters:
        /// - shape: The shape
        /// - dataType: The data type
        /// - strides: The strides.
        #[unsafe(method(initWithShape:dataType:strides:))]
        #[unsafe(method_family = init)]
        pub unsafe fn initWithShape_dataType_strides(
            this: Allocated<Self>,
            shape: &NSArray<NSNumber>,
            data_type: MLMultiArrayDataType,
            strides: &NSArray<NSNumber>,
        ) -> Retained<Self>;

        #[cfg(feature = "block2")]
        /// Creates the object with existing data without copy.
        ///
        /// Use this initializer to reference the existing buffer as the storage without copy.
        ///
        /// ```objc
        /// int32_t *buffer = malloc(sizeof(int32_t) * 2 * 3 * 4);
        /// MLMultiArray *multiArray = [[MLMultiArray alloc] initWithDataPointer:buffer
        /// shape:
        /// @
        /// [
        /// @
        /// 2,
        /// @
        /// 3,
        /// @
        /// 4]
        /// dataType:MLMultiArrayDataTypeInt32
        /// strides:
        /// @
        /// [
        /// @
        /// 12,
        /// @
        /// 4,
        /// @
        /// 1]
        /// deallocator:^(void *bytes) { free(bytes); }
        /// error:NULL];
        /// ```
        ///
        /// - Parameters:
        /// - dataPointer: The pointer to the buffer.
        /// - shape: The shape
        /// - dataType: The data type
        /// - strides: The strides.
        /// - deallocator: Block to be called on the deallocation of the instance.
        /// - error: Filled with error information on error.
        ///
        /// # Safety
        ///
        /// `data_pointer` must be a valid pointer.
        #[unsafe(method(initWithDataPointer:shape:dataType:strides:deallocator:error:_))]
        #[unsafe(method_family = init)]
        pub unsafe fn initWithDataPointer_shape_dataType_strides_deallocator_error(
            this: Allocated<Self>,
            data_pointer: NonNull<c_void>,
            shape: &NSArray<NSNumber>,
            data_type: MLMultiArrayDataType,
            strides: &NSArray<NSNumber>,
            deallocator: Option<&block2::DynBlock<dyn Fn(NonNull<c_void>)>>,
        ) -> Result<Retained<Self>, Retained<NSError>>;

        #[cfg(feature = "objc2-core-video")]
        /// Create by wrapping a pixel buffer.
        ///
        /// Use this initializer to create an IOSurface backed MLMultiArray, which can reduce the inference latency by avoiding the buffer copy.
        ///
        /// The instance will own the pixel buffer and release it on the deallocation.
        ///
        /// The pixel buffer's pixel format type must be either `kCVPixelFormatType_OneComponent16Half` for `MLMultiArrayDataTypeFloat16` or
        /// `kCVPixelFormatType_OneComponent8` for `MLMultiArrayDataTypeInt8`.
        ///
        /// ```objc
        /// CVPixelBufferRef pixelBuffer = NULL;
        /// NSDictionary* pixelBufferAttributes =
        /// @
        /// {
        /// (id)kCVPixelBufferIOSurfacePropertiesKey:
        /// @
        /// {}
        /// };
        ///
        /// // Since shape == [2, 3, 4], width is 4 (= shape[2]) and height is 6 (= shape[0] * shape[1]).
        /// CVPixelBufferCreate(kCFAllocatorDefault, 4, 6, kCVPixelFormatType_OneComponent16Half, (__bridge CFDictionaryRef)pixelBufferAttributes,
        /// &pixelBuffer
        /// );
        /// MLMultiArray *multiArray = [[MLMultiArray alloc] initWithPixelBuffer:pixelBuffer shape:
        /// @
        /// [
        /// @
        /// 2,
        /// @
        /// 3,
        /// @
        /// 4]];
        /// ```
        ///
        /// - Parameters:
        /// - pixelBuffer: The pixel buffer to be owned by the instance.
        /// - shape: The shape of the MLMultiArray. The last dimension of `shape` must match the pixel buffer's width. The product of the rest of the dimensions must match the height.
        #[unsafe(method(initWithPixelBuffer:shape:))]
        #[unsafe(method_family = init)]
        pub unsafe fn initWithPixelBuffer_shape(
            this: Allocated<Self>,
            pixel_buffer: &CVPixelBuffer,
            shape: &NSArray<NSNumber>,
        ) -> Retained<Self>;
    );
}

/// ScopedBufferAccess.
impl MLMultiArray {
    extern_methods!(
        #[cfg(feature = "block2")]
        /// Get the underlying buffer pointer to read.
        ///
        /// The buffer pointer is valid only within the block.
        ///
        /// ```objc
        /// MLMultiArray * A = [[MLMultiArray alloc] initWithShape:
        /// @
        /// [
        /// @
        /// 3,
        /// @
        /// 2] dataType:MLMultiArrayDataTypeInt32 error:NULL];
        /// A[
        /// @
        /// [
        /// @
        /// 1,
        /// @
        /// 2]] =
        /// @
        /// 42;
        /// [A getBytesWithHandler:^(const void *bytes, NSInteger size) {
        /// const int32_t *scalarBuffer = (const int32_t *)bytes;
        /// const int strideY = A.strides[0].intValue;
        /// // Print 42
        /// NSLog(
        /// "
        /// Scalar at (1, 2): %d", scalarBuffer[1 * strideY + 2]);
        /// }];
        /// ```
        /// - Parameters:
        /// - handler: The block to receive the buffer pointer and its size in bytes.
        #[unsafe(method(getBytesWithHandler:))]
        #[unsafe(method_family = none)]
        pub unsafe fn getBytesWithHandler(
            &self,
            handler: &block2::DynBlock<dyn Fn(NonNull<c_void>, NSInteger) + '_>,
        );

        #[cfg(feature = "block2")]
        /// Get the underlying buffer pointer to mutate.
        ///
        /// The buffer pointer is valid only within the block.
        ///
        /// Use `strides` parameter passed in the block because the method may switch to a new backing buffer with different strides.
        ///
        /// ```objc
        /// MLMultiArray * A = [[MLMultiArray alloc] initWithShape:
        /// @
        /// [
        /// @
        /// 3,
        /// @
        /// 2] dataType:MLMultiArrayDataTypeInt32 error:NULL];
        /// [A getMutableBytesWithHandler:^(void *bytes, NSInteger __unused size, NSArray
        /// <NSNumber
        /// *> *strides) {
        /// int32_t *scalarBuffer = (int32_t *)bytes;
        /// const int strideY = strides[0].intValue;
        /// scalarBuffer[1 * strideY + 2] = 42;  // Set 42 at A[1, 2]
        /// }];
        /// ```
        ///
        /// - Parameters:
        /// - handler: The block to receive the buffer pointer, size in bytes, and strides.
        #[unsafe(method(getMutableBytesWithHandler:))]
        #[unsafe(method_family = none)]
        pub unsafe fn getMutableBytesWithHandler(
            &self,
            handler: &block2::DynBlock<
                dyn Fn(NonNull<c_void>, NSInteger, NonNull<NSArray<NSNumber>>) + '_,
            >,
        );
    );
}

/// Concatenating.
impl MLMultiArray {
    extern_methods!(
        /// Concatenate MLMultiArrays to form a new MLMultiArray.
        ///
        /// All the source MLMultiArrays must have a same shape except the specified axis. The resultant
        /// MLMultiArray has the same shape as inputs except this axis, which dimension will be the sum of
        /// all the input dimensions of the axis.
        ///
        /// For example,
        ///
        /// ```swift
        /// // Swift
        /// let A = try MLMultiArray(shape: [2, 3], dataType: .int32)
        /// let B = try MLMultiArray(shape: [2, 2], dataType: .int32)
        /// let C = MLMultiArray(concatenating: [A, B], axis: 1, dataType: .int32)
        /// assert(C.shape == [2, 5])
        /// ```
        ///
        /// ```objc
        /// // Obj-C
        /// MLMultiArray *A = [[MLMultiArray alloc] initWithShape:
        /// @
        /// [
        /// @
        /// 2,
        /// @
        /// 3] dataType:MLMultiArrayDataTypeInt32 error:NULL];
        /// MLMultiArray *B = [[MLMultiArray alloc] initWithShape:
        /// @
        /// [
        /// @
        /// 2,
        /// @
        /// 2] dataType:MLMultiArrayDataTypeInt32 error:NULL];
        /// MLMultiArray *C = [MLMultiArray multiArrayByConcatenatingMultiArrays:
        /// @
        /// [A, B] alongAxis:1 dataType:MLMultiArrayDataTypeInt32];
        /// assert(C.shape ==
        /// @
        /// [
        /// @
        /// 2,
        /// @
        /// 5])
        /// ```
        ///
        /// Numeric data will be up or down casted as needed.
        ///
        /// The method raises NSInvalidArgumentException if the shapes of input multi arrays are not
        /// compatible for concatenation.
        ///
        /// - Parameters:
        /// - multiArrays: Array of MLMultiArray instances to be concatenated.
        /// - axis: Axis index with which the concatenation will performed. The value is wrapped by the dimension of the axis. For example, -1 is the last axis.
        /// - dataType: The data type of the resultant MLMultiArray.
        #[unsafe(method(multiArrayByConcatenatingMultiArrays:alongAxis:dataType:))]
        #[unsafe(method_family = none)]
        pub unsafe fn multiArrayByConcatenatingMultiArrays_alongAxis_dataType(
            multi_arrays: &NSArray<MLMultiArray>,
            axis: NSInteger,
            data_type: MLMultiArrayDataType,
        ) -> Retained<Self>;
    );
}

/// NSNumberDataAccess.
impl MLMultiArray {
    extern_methods!(
        /// Get a value by its linear index (assumes C-style index ordering)
        #[unsafe(method(objectAtIndexedSubscript:))]
        #[unsafe(method_family = none)]
        pub unsafe fn objectAtIndexedSubscript(&self, idx: NSInteger) -> Retained<NSNumber>;

        /// Get a value by its multidimensional index (NSArray
        /// <NSNumber
        /// *>)
        #[unsafe(method(objectForKeyedSubscript:))]
        #[unsafe(method_family = none)]
        pub unsafe fn objectForKeyedSubscript(&self, key: &NSArray<NSNumber>)
            -> Retained<NSNumber>;

        /// Set a value by its linear index (assumes C-style index ordering)
        #[unsafe(method(setObject:atIndexedSubscript:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setObject_atIndexedSubscript(&self, obj: &NSNumber, idx: NSInteger);

        /// Set a value by subindicies (NSArray
        /// <NSNumber
        /// *>)
        #[unsafe(method(setObject:forKeyedSubscript:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setObject_forKeyedSubscript(&self, obj: &NSNumber, key: &NSArray<NSNumber>);
    );
}

/// Transferring.
impl MLMultiArray {
    extern_methods!(
        /// Transfer the contents to the destination multi-array.
        ///
        /// Numeric data will be up or down casted as needed. It can transfer to a multi-array with different layout (strides).
        ///
        /// ```swift
        /// let sourceMultiArray: MLMultiArray = ... // shape is [2, 3] and data type is Float64
        ///
        /// let newStrides = [4, 1]
        /// let destinationMultiArray = MLMultiArray(shape: [2, 3],
        /// dataType: .float32,
        /// strides: newStrides)
        /// sourceMultiArray.transfer(to: destinationMultiArray)
        /// ```
        ///
        /// ```objc
        /// NSArray
        /// <NSNumber
        /// *> *shape =
        /// @
        /// [
        /// @
        /// 2,
        /// @
        /// 3];
        /// NSArray
        /// <NSNumber
        /// *> *sourceStrides =
        /// @
        /// [
        /// @
        /// 3,
        /// @
        /// 1];
        /// NSArray
        /// <NSNumber
        /// *> *destinationStrides =
        /// @
        /// [
        /// @
        /// 4,
        /// @
        /// 1];
        /// MLMultiArray *source = [[MLMultiArray alloc] initWithShape:shape
        /// dataType:MLMultiArrayDataTypeDouble
        /// strides:sourceStrides];
        /// // Initialize source...
        ///
        /// MLMultiArray *destination = [[MLMultiArray alloc] initWithShape:shape
        /// dataType:MLMultiArrayDataTypeFloat32
        /// strides:destinationStrides];
        /// [source transferToMultiArray:destination];
        /// ```
        ///
        /// - Parameters:
        /// - destinationMultiArray: The transfer destination.
        #[unsafe(method(transferToMultiArray:))]
        #[unsafe(method_family = none)]
        pub unsafe fn transferToMultiArray(&self, destination_multi_array: &MLMultiArray);
    );
}