Skip to content

Instantly share code, notes, and snippets.

@martinmroz
Created December 29, 2021 07:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save martinmroz/5905c65e129d22a1b56d84f08b35a0f4 to your computer and use it in GitHub Desktop.
Save martinmroz/5905c65e129d22a1b56d84f08b35a0f4 to your computer and use it in GitHub Desktop.
Rust -> NSString -> String Bridge
/*
* Copyright (C) 2019 Martin Mroz
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface NSString (Bcbp)
/**
Creates an NSString wrapping the `Bcbp` owned and managed C string.
Ownership of the pointer is transferred to the new instance of the receiver.
No data is copied, and the contents is deallocated using the appropriate
FFI method once no longer required.
@return A new instance of the receiver taking ownership of the input, or nil if the input is nil.
*/
+ (_Nullable instancetype)IB_stringWithBcbpManagedCStringNoCopy:(char * _Nullable)bcbpCString;
/**
Creates an NSString wrapping the `Bcbp` owned and managed C string.
Ownership of the pointer is transferred to the new instance of the receiver.
No data is copied, and the contents is deallocated using the appropriate
FFI method once no longer required.
@param length The pre-determined length of the `bcbpCString` in bytes.
@return A new instance of the receiver taking ownership of the input, or nil if the input is nil.
*/
+ (_Nullable instancetype)IB_stringWithBcbpManagedCStringNoCopy:(char * _Nullable)bcbpCString length:(NSUInteger)length;
@end
NS_ASSUME_NONNULL_END
/*
* Copyright (C) 2019 Martin Mroz
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
#include "iata_bcbp_ffi.h"
#import "NSString+Bcbp.h"
// Deallocates a string allocated by the Bcbp FFI library.
static void BcbpCStringDeallocatorDeallocate(void *ptr, void *info)
{
BcbpDestroyString((char *)ptr);
}
// Not valid for allocation, a CFAllocatorRef build from this context
// is used to defer destruction of strings managed by the Bcbp FFI library.
// As a Rust library may not use the system allocator, all pointers returned from
// the FFI library must be destroyed therewith. To reduce allocations and avoid
// copying all strings into memory managed by the system allocator,
// the memory is used directly and destruction is deferred back to the library.
static CFAllocatorContext BcbpCStringDeallocatorContext = {
.version = 0,
.info = NULL,
.retain = NULL,
.release = NULL,
.copyDescription = NULL,
.allocate = NULL,
.reallocate = NULL,
.deallocate = BcbpCStringDeallocatorDeallocate,
.preferredSize = NULL,
};
@implementation NSString (Bcbp)
+ (instancetype)IB_stringWithBcbpManagedCStringNoCopy:(char *)bcbpCString;
{
return [self IB_stringWithBcbpManagedCStringNoCopy:bcbpCString length:strlen(bcbpCString)];
}
+ (instancetype)IB_stringWithBcbpManagedCStringNoCopy:(char *)bcbpCString length:(NSUInteger)length;
{
if (bcbpCString == NULL) {
return nil;
}
static CFAllocatorRef bcbpCStringDeallocator = NULL;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
bcbpCStringDeallocator = CFAllocatorCreate(kCFAllocatorDefault, &BcbpCStringDeallocatorContext);
});
CFStringRef const managedString = CFStringCreateWithBytesNoCopy(
kCFAllocatorDefault,
(const UInt8 *)bcbpCString,
length,
kCFStringEncodingUTF8,
false,
bcbpCStringDeallocator
);
return CFBridgingRelease(managedString);
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment