Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ exports[`GenerateModuleObjCpp can generate a header file NativeModule specs 1`]
#import <RCTRequired/RCTRequired.h>
#import <RCTTypeSafety/RCTConvertHelpers.h>
#import <RCTTypeSafety/RCTTypedModuleConstants.h>
#import <React/RCTArrayBuffer.h>
#import <React/RCTBridgeModule.h>
#import <React/RCTCxxConvert.h>
#import <React/RCTManagedPointer.h>
Expand Down Expand Up @@ -1578,6 +1579,7 @@ exports[`GenerateModuleObjCpp can generate a header file NativeModule specs with
#import <RCTRequired/RCTRequired.h>
#import <RCTTypeSafety/RCTConvertHelpers.h>
#import <RCTTypeSafety/RCTTypedModuleConstants.h>
#import <React/RCTArrayBuffer.h>
#import <React/RCTBridgeModule.h>
#import <React/RCTCxxConvert.h>
#import <React/RCTManagedPointer.h>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ const HeaderFileTemplate = ({
#import <RCTRequired/RCTRequired.h>
#import <RCTTypeSafety/RCTConvertHelpers.h>
#import <RCTTypeSafety/RCTTypedModuleConstants.h>
#import <React/RCTArrayBuffer.h>
#import <React/RCTBridgeModule.h>
#import <React/RCTCxxConvert.h>
#import <React/RCTManagedPointer.h>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ function getParamObjCType(
return notStruct(wrapOptional('NSArray *', !nullable));
}
case 'ArrayBufferTypeAnnotation': {
return notStruct(wrapOptional('NSData *', !nullable));
return notStruct(wrapOptional('RCTArrayBuffer *', !nullable));
}
}

Expand Down Expand Up @@ -398,7 +398,7 @@ function getReturnObjCType(
case 'GenericObjectTypeAnnotation':
return wrapOptional('NSDictionary *', isRequired);
case 'ArrayBufferTypeAnnotation':
return wrapOptional('NSMutableData *', isRequired);
return wrapOptional('RCTArrayBuffer *', isRequired);
default:
typeAnnotation.type as 'MixedTypeAnnotation';
throw new Error(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ Map {
#import <RCTRequired/RCTRequired.h>
#import <RCTTypeSafety/RCTConvertHelpers.h>
#import <RCTTypeSafety/RCTTypedModuleConstants.h>
#import <React/RCTArrayBuffer.h>
#import <React/RCTBridgeModule.h>
#import <React/RCTCxxConvert.h>
#import <React/RCTManagedPointer.h>
Expand Down Expand Up @@ -92,6 +93,7 @@ Map {
#import <RCTRequired/RCTRequired.h>
#import <RCTTypeSafety/RCTConvertHelpers.h>
#import <RCTTypeSafety/RCTTypedModuleConstants.h>
#import <React/RCTArrayBuffer.h>
#import <React/RCTBridgeModule.h>
#import <React/RCTCxxConvert.h>
#import <React/RCTManagedPointer.h>
Expand All @@ -102,9 +104,9 @@ Map {

@protocol NativeSampleTurboModuleSpec <RCTBridgeModule, RCTTurboModule>

- (NSMutableData *)getArrayBuffer;
- (void)voidArrayBuffer:(NSData *)arg;
- (void)voidNullableArrayBuffer:(NSData * _Nullable)arg;
- (RCTArrayBuffer *)getArrayBuffer;
- (void)voidArrayBuffer:(RCTArrayBuffer *)arg;
- (void)voidNullableArrayBuffer:(RCTArrayBuffer * _Nullable)arg;

@end

Expand Down Expand Up @@ -159,6 +161,7 @@ Map {
#import <RCTRequired/RCTRequired.h>
#import <RCTTypeSafety/RCTConvertHelpers.h>
#import <RCTTypeSafety/RCTTypedModuleConstants.h>
#import <React/RCTArrayBuffer.h>
#import <React/RCTBridgeModule.h>
#import <React/RCTCxxConvert.h>
#import <React/RCTManagedPointer.h>
Expand Down Expand Up @@ -200,6 +203,7 @@ Map {
#import <RCTRequired/RCTRequired.h>
#import <RCTTypeSafety/RCTConvertHelpers.h>
#import <RCTTypeSafety/RCTTypedModuleConstants.h>
#import <React/RCTArrayBuffer.h>
#import <React/RCTBridgeModule.h>
#import <React/RCTCxxConvert.h>
#import <React/RCTManagedPointer.h>
Expand Down Expand Up @@ -475,6 +479,7 @@ Map {
#import <RCTRequired/RCTRequired.h>
#import <RCTTypeSafety/RCTConvertHelpers.h>
#import <RCTTypeSafety/RCTTypedModuleConstants.h>
#import <React/RCTArrayBuffer.h>
#import <React/RCTBridgeModule.h>
#import <React/RCTCxxConvert.h>
#import <React/RCTManagedPointer.h>
Expand Down Expand Up @@ -516,6 +521,7 @@ Map {
#import <RCTRequired/RCTRequired.h>
#import <RCTTypeSafety/RCTConvertHelpers.h>
#import <RCTTypeSafety/RCTTypedModuleConstants.h>
#import <React/RCTArrayBuffer.h>
#import <React/RCTBridgeModule.h>
#import <React/RCTCxxConvert.h>
#import <React/RCTManagedPointer.h>
Expand Down Expand Up @@ -581,6 +587,7 @@ Map {
#import <RCTRequired/RCTRequired.h>
#import <RCTTypeSafety/RCTConvertHelpers.h>
#import <RCTTypeSafety/RCTTypedModuleConstants.h>
#import <React/RCTArrayBuffer.h>
#import <React/RCTBridgeModule.h>
#import <React/RCTCxxConvert.h>
#import <React/RCTManagedPointer.h>
Expand Down Expand Up @@ -651,6 +658,7 @@ Map {
#import <RCTRequired/RCTRequired.h>
#import <RCTTypeSafety/RCTConvertHelpers.h>
#import <RCTTypeSafety/RCTTypedModuleConstants.h>
#import <React/RCTArrayBuffer.h>
#import <React/RCTBridgeModule.h>
#import <React/RCTCxxConvert.h>
#import <React/RCTManagedPointer.h>
Expand Down Expand Up @@ -836,6 +844,7 @@ Map {
#import <RCTRequired/RCTRequired.h>
#import <RCTTypeSafety/RCTConvertHelpers.h>
#import <RCTTypeSafety/RCTTypedModuleConstants.h>
#import <React/RCTArrayBuffer.h>
#import <React/RCTBridgeModule.h>
#import <React/RCTCxxConvert.h>
#import <React/RCTManagedPointer.h>
Expand Down Expand Up @@ -1104,6 +1113,7 @@ Map {
#import <RCTRequired/RCTRequired.h>
#import <RCTTypeSafety/RCTConvertHelpers.h>
#import <RCTTypeSafety/RCTTypedModuleConstants.h>
#import <React/RCTArrayBuffer.h>
#import <React/RCTBridgeModule.h>
#import <React/RCTCxxConvert.h>
#import <React/RCTManagedPointer.h>
Expand Down Expand Up @@ -1233,6 +1243,7 @@ Map {
#import <RCTRequired/RCTRequired.h>
#import <RCTTypeSafety/RCTConvertHelpers.h>
#import <RCTTypeSafety/RCTTypedModuleConstants.h>
#import <React/RCTArrayBuffer.h>
#import <React/RCTBridgeModule.h>
#import <React/RCTCxxConvert.h>
#import <React/RCTManagedPointer.h>
Expand Down Expand Up @@ -1298,6 +1309,7 @@ Map {
#import <RCTRequired/RCTRequired.h>
#import <RCTTypeSafety/RCTConvertHelpers.h>
#import <RCTTypeSafety/RCTTypedModuleConstants.h>
#import <React/RCTArrayBuffer.h>
#import <React/RCTBridgeModule.h>
#import <React/RCTCxxConvert.h>
#import <React/RCTManagedPointer.h>
Expand Down Expand Up @@ -1389,6 +1401,7 @@ Map {
#import <RCTRequired/RCTRequired.h>
#import <RCTTypeSafety/RCTConvertHelpers.h>
#import <RCTTypeSafety/RCTTypedModuleConstants.h>
#import <React/RCTArrayBuffer.h>
#import <React/RCTBridgeModule.h>
#import <React/RCTCxxConvert.h>
#import <React/RCTManagedPointer.h>
Expand Down
64 changes: 64 additions & 0 deletions packages/react-native/React/Base/RCTArrayBuffer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

/**
* A fixed-length byte buffer shared between JS `ArrayBuffer`s and ObjC TurboModules. Fixed
* length lets the backing store alias JS memory; `NSMutableData` cannot do that.
*
* `isOwningBytes`:
* - `YES` — safe to retain and use from any thread (synchronize if aliasing JS
* memory).
* - `NO` — valid only during the synchronous call on the calling thread; copy with
* `arrayBufferWithCopiedBytes:length:` to keep the bytes.
*/
@interface RCTArrayBuffer : NSObject

/**
* NULL when `length` is 0, non-NULL otherwise, matching `NSData.bytes`.
*/
@property (nonatomic, readonly, nullable) void *mutableBytes NS_RETURNS_INNER_POINTER;

@property (nonatomic, readonly) NSUInteger length;

/** Whether the buffer owns its bytes. See the class comment. */
@property (nonatomic, readonly, getter=isOwningBytes) BOOL owningBytes;

/**
* A new zero-filled owning buffer.
*/
+ (instancetype)arrayBufferWithLength:(NSUInteger)length;

/**
* A new owning buffer holding a copy of `bytes`. Passing NULL zero-fills.
*/
+ (instancetype)arrayBufferWithCopiedBytes:(nullable const void *)bytes length:(NSUInteger)length;

/**
* An owning buffer aliasing `bytes` without copying. If `cleanup` is non-nil, it runs on dealloc,
* like `-[NSData dataWithBytesNoCopy:length:freeWhenDone:YES]`; if nil, the caller must keep
* `bytes` valid until dealloc. NULL `bytes` with non-zero `length` raises NSInvalidArgumentException.
*/
+ (instancetype)arrayBufferWithOwnedBytes:(nullable void *)bytes
length:(NSUInteger)length
cleanup:(nullable void (^)(void))cleanup;

/**
* A non-owning, zero-copy alias of `bytes`. See the class comment for lifetime rules. NULL `bytes`
* with non-zero `length` raises NSInvalidArgumentException.
*/
+ (instancetype)arrayBufferWithUnownedBytes:(nullable void *)bytes length:(NSUInteger)length;

- (instancetype)init NS_UNAVAILABLE;
+ (instancetype)new NS_UNAVAILABLE;

@end

NS_ASSUME_NONNULL_END
127 changes: 127 additions & 0 deletions packages/react-native/React/Base/RCTArrayBuffer.mm
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

#import "RCTArrayBuffer.h"

@interface RCTArrayBuffer ()

- (instancetype)initWithBytesNoCopy:(nullable void *)bytes
length:(NSUInteger)length
owningBytes:(BOOL)owningBytes
cleanup:(nullable void (^)(void))cleanup NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithCopiedBytes:(nullable const void *)bytes length:(NSUInteger)length;

@end

@implementation RCTArrayBuffer {
void *_bytes;
NSUInteger _length;
BOOL _owningBytes;
void (^_cleanup)(void);
}

#pragma mark - Initializers

- (instancetype)initWithBytesNoCopy:(void *)bytes
length:(NSUInteger)length
owningBytes:(BOOL)owningBytes
cleanup:(void (^)(void))cleanup
{
if (bytes == NULL && length != 0) {
[NSException raise:NSInvalidArgumentException
format:@"RCTArrayBuffer: NULL bytes with length %lu", (unsigned long)length];
}

if (self = [super init]) {
_bytes = bytes;
_length = length;
_owningBytes = owningBytes;
_cleanup = [cleanup copy];
}
return self;
}

- (instancetype)initWithCopiedBytes:(const void *)bytes length:(NSUInteger)length
{
if (length == 0) {
return [self initWithBytesNoCopy:NULL length:0 owningBytes:YES cleanup:nil];
}

void *copy = malloc(length);
if (copy == NULL) {
[NSException raise:NSMallocException format:@"RCTArrayBuffer: failed to allocate %lu bytes", (unsigned long)length];
}
if (bytes != NULL) {
memcpy(copy, bytes, length);
} else {
memset(copy, 0, length);
}

return [self initWithBytesNoCopy:copy
length:length
owningBytes:YES
cleanup:^{
free(copy);
}];
}

+ (instancetype)arrayBufferWithLength:(NSUInteger)length
{
return [[self alloc] initWithCopiedBytes:NULL length:length];
}

+ (instancetype)arrayBufferWithCopiedBytes:(const void *)bytes length:(NSUInteger)length
{
return [[self alloc] initWithCopiedBytes:bytes length:length];
}

+ (instancetype)arrayBufferWithOwnedBytes:(void *)bytes
length:(NSUInteger)length
cleanup:(nullable void (^)(void))cleanup
{
return [[self alloc] initWithBytesNoCopy:bytes length:length owningBytes:YES cleanup:cleanup];
}

+ (instancetype)arrayBufferWithUnownedBytes:(void *)bytes length:(NSUInteger)length
{
return [[self alloc] initWithBytesNoCopy:bytes length:length owningBytes:NO cleanup:nil];
}

#pragma mark - Accessors

- (void *)mutableBytes
{
return _bytes;
}

- (NSUInteger)length
{
return _length;
}

- (BOOL)isOwningBytes
{
return _owningBytes;
}

- (NSString *)description
{
return [NSString stringWithFormat:@"<%@: %p; length = %lu; owningBytes = %@>",
NSStringFromClass([self class]),
self,
(unsigned long)_length,
_owningBytes ? @"YES" : @"NO"];
}

- (void)dealloc
{
if (_cleanup != nil) {
_cleanup();
}
}

@end
Loading
Loading