Swift 5 : how to deallocate memory, allocated by shared library - swift

I have the following C function inside a shared library :
int GetRxDataBlock( char** data )
{
CHECK_FACADE_INITIALIZATION( "getRxDataBlock : Client facade not initialized", __LINE__ );
if ( data == nullptr ) {
printErrorMsg("getRxDataBlock : nullptr", __LINE__);
return -1;
}
int ret = 0;
try {
std::string rxData = g_facade.value()->getRxDataBlock();
*data = (char*) malloc(rxData.size() + 1);
memset(*data, 0, rxData.size() + 1 );
memcpy(*data, rxData.c_str(), rxData.size());
}catch(...) {
ret = -1;
}
return ret;
}
And this is the way I call it from Swift code :
var rxData: UnsafeMutablePointer? = nil
let apiResponse = GetRxDataBlock(&rxData)
print("Rx data : ret = \(apiResponse)")
if let dataStr = rxData {
let rxStr = String(cString: dataStr)
print("Rx data = \(rxStr)")
}
What is the correct way to deallocate memory returned by GetRxDataBlock function ?

malloc()ed memory must be released with free():
if let dataStr = rxData {
// do something with `dataStr`
// ...
free(dataStr)
}
This is also a good use-case for defer, which calls the closure just before the scope of the block is left:
if let dataStr = rxData {
defer { free(dataStr) }
// do something with `dataStr`
// ...
}
On Apple platforms, free() is imported from the standard C library as part of the Darwin module (which is imported by Foundation, AppKit, or UIKit). On Linux you would import Glibc.

Related

How can I handle raw bytes on dart?

I'm totally new at app developing.
I trying to communicate with C-written end device via raw UDP packet. (such a modbus-like protocol)
And I'm suffering pain with serial/deserializing class(struct).
Here is a simple class, Packet which contain uint32, uint16, uint8.
Pack() is working, but are there any better way to achieve that?
I don't know how can I implement Unpack() method. I mean, how can I convert Uint8List to int?
import 'dart:typed_data';
void main() {
var pkt = new Packet();
pkt.TID = 0x01234567;
pkt.Src = 0x89;
pkt.Des = 0xab;
pkt.Data = 0xcdef;
var buf = pkt.Pack();
print('Packed: ${buf}');
var pkt_2 = new Packet();
if (pkt_2.Unpack(buf) != null) {
print("panic!");
return;
}
print('UnPacked: ${pkt_2.toString()}');
}
class Packet {
int TID; // uint32
int Src; // uint8
int Des; // uint8
int Data; // uint16
static const SIZE = 8;
String toString() {
return 'TID: ${TID.toRadixString(16)}, Src:${Src.toRadixString(16)}, Des:${Des.toRadixString(16)}, Data:${Data.toRadixString(16)}';
}
Uint8List Pack() {
var buf = Byteconv.itou32(TID) +
Byteconv.itou8(Src) +
Byteconv.itou8(Des) +
Byteconv.itou16(Data);
return Uint8List.fromList(buf);
}
Error Unpack(Uint8List buf) {
if (buf.length != SIZE) {
return Error();
}
// What can I do?
// TID =
// Src =
// Des =
// Data =
return null;
}
}
class Byteconv {
static Uint8List itou64(int val) {
return Uint8List(8)..buffer.asByteData().setUint64(0, val, Endian.big);
}
static Uint8List itou32(int val) {
return Uint8List(4)..buffer.asByteData().setUint32(0, val, Endian.big);
}
static Uint8List itou16(int val) {
return Uint8List(2)..buffer.asByteData().setUint16(0, val, Endian.big);
}
static Uint8List itou8(int u8) {
return Uint8List(1)..buffer.asUint8List()[0] = u8;
}
}
SOLVED
var buf_view = ByteData.sublistView(buf);
TID = buf_view.getUint32(0);
Src = buf_view.getUint8(4);
Des = buf_view.getUint8(5);
Data = buf_view.getUint16(6);

alternative to using 'await' with lazy_static! macro in rust?

I want to use Async MongoDB in a project.
I don't want to pass around the client because it would need to go around multiple tasks and threads. So I kept a static client using lazy_static. However, I can't use await in the initialization block.
What can I do to work around this?
Suggestions for doing it without lazy_static are also welcome.
use std::env;
use futures::stream::StreamExt;
use mongodb::{
bson::{doc, Bson},
options::ClientOptions,
Client,
};
lazy_static! {
static ref MONGO: Option<Client> = {
if let Ok(token) = env::var("MONGO_AUTH") {
if let Ok(client_options) = ClientOptions::parse(&token).await
^^^^^
{
if let Ok(client) = Client::with_options(client_options) {
return Some(client);
}
}
}
return None;
};
}
I went with this approach based on someone's suggestion in rust forums.
static MONGO: OnceCell<Client> = OnceCell::new();
static MONGO_INITIALIZED: OnceCell<tokio::sync::Mutex<bool>> = OnceCell::new();
pub async fn get_mongo() -> Option<&'static Client> {
// this is racy, but that's OK: it's just a fast case
let client_option = MONGO.get();
if let Some(_) = client_option {
return client_option;
}
// it hasn't been initialized yet, so let's grab the lock & try to
// initialize it
let initializing_mutex = MONGO_INITIALIZED.get_or_init(|| tokio::sync::Mutex::new(false));
// this will wait if another task is currently initializing the client
let mut initialized = initializing_mutex.lock().await;
// if initialized is true, then someone else initialized it while we waited,
// and we can just skip this part.
if !*initialized {
// no one else has initialized it yet, so
if let Ok(token) = env::var("MONGO_AUTH") {
if let Ok(client_options) = ClientOptions::parse(&token).await {
if let Ok(client) = Client::with_options(client_options) {
if let Ok(_) = MONGO.set(client) {
*initialized = true;
}
}
}
}
}
drop(initialized);
MONGO.get()
}
However I can't use await in the initialization block.
You can skirt this with futures::executor::block_on
use once_cell::sync::Lazy;
// ...
static PGCLIENT: Lazy<Client> = Lazy::new(|| {
let client: Client = futures::executor::block_on(async {
let (client, connection) = tokio_postgres::connect(
"postgres:///?user=ecarroll&port=5432&host=/run/postgresql",
NoTls,
)
.await
.unwrap();
tokio::spawn(async move {
if let Err(e) = connection.await {
eprintln!("connection error: {}", e);
}
});
client
});
client
});
What we have is a non-async closure blocking in a single thread until the resolution of the future.
Create a new runtime from tokio::runtime::Runtime and use block_on to block the current thread until completion.
// database.rs
use tokio::runtime::Runtime;
use mongodb::Client;
pub fn connect_sync() -> Client {
Runtime::new().unwrap().block_on(async {
Client::with_uri_str("mongodb://localhost:27017").await.unwrap()
})
}
// main.rs
mod database;
lazy_static! {
static ref CLIENT: mongodb::Client = database::connect_sync();
}
#[actix_web::main]
async fn main() {
let collection = &CLIENT.database("db_name").collection("coll_name");
// ...
}
Use the async_once crate.
use async_once::AsyncOnce;
use lazy_static::lazy_static;
use mongodb::Client;
lazy_static! {
static ref CLIENT: AsyncOnce<Client> = AsyncOnce::new(async {
Client::with_uri_str(std::env::var("MONGO_URL").expect("MONGO_URL not set"))
.await
.unwrap()
});
}
then
CLIENT.get().await;

Wrapping libcups C library in Swift

I am trying to wrap the libcups library https://github.com/apple/cups to be used in my Swift project.
I have tried some of the examples in https://www.cups.org/doc/cupspm.html and they are working fine.
However I am struggling when it comes to wrapping the C code to be used in a Swift project.
I have been searching online on how to wrap C libraries in Swift but has not been able to have much progress.
Here is the C code
#include <stdio.h>
#include <cups/cups.h>
typedef struct {
int num_dests;
cups_dest_t *dests;
} my_user_data_t;
int my_dest_cb(my_user_data_t *user_data, unsigned flags, cups_dest_t *dest) {
if (flags & CUPS_DEST_FLAGS_REMOVED) {
user_data->num_dests = cupsRemoveDest(dest->name, dest->instance, user_data->num_dests, &(user_data->dests));
} else {
user_data->num_dests = cupsCopyDest(dest, user_data->num_dests, &(user_data->dests));
}
return 1;
}
int my_get_dests(cups_ptype_t type, cups_ptype_t mask, cups_dest_t **dests) {
my_user_data_t user_data = { 0, NULL };
if (!cupsEnumDests(CUPS_DEST_FLAGS_NONE, 1000, NULL, type, mask, (cups_dest_cb_t)my_dest_cb, &user_data)) {
cupsFreeDests(user_data.num_dests, user_data.dests);
*dests = NULL;
return 0;
} else {
*dests = user_data.dests;
return user_data.num_dests;
}
}
int main(int argc, const char * argv[]) {
cups_dest_t *dests = NULL;
int num_dests = my_get_dests(0, 0, &dests);
printf("Destination found: %d\n", num_dests);
cups_dest_t *dest;
int i;
const char *value;
for (i = num_dests, dest = dests; i > 0; i--, dest++) {
if (dest->instance == NULL) {
value = cupsGetOption("printer-info", dest->num_options, dest->options);
printf("%s (%s)\n", dest->name, value ? value : "No description");
}
}
return 0;
}
Here is the same thing but in Swift
let destinationsCallback: cups_dest_cb_t = { user_data, flags, dest in
// (void *user_data, unsigned flags, cups_dest_t *dest)
var userDataPointer = user_data!.assumingMemoryBound(to: my_user_data_t.self).pointee
var destData = dest!.pointee
if destData.instance != nil {
print("\(String(cString: destData.name))/\(String(cString: destData.instance))")
} else {
print(String(cString: destData.name))
}
if flags == CUPS_DEST_FLAGS_REMOVED {
userDataPointer.num_dests = cupsRemoveDest(destData.name, destData.instance, userDataPointer.num_dests, &(userDataPointer.dests))
} else {
userDataPointer.num_dests = cupsCopyDest(dest, userDataPointer.num_dests, &(userDataPointer.dests))
}
return 1
}
func getDestinations(type: UInt32, mask: UInt32, dests: UnsafeMutablePointer<cups_dest_t>) -> Int32 {
var userData = my_user_data_t(num_dests: 0, dests: nil)
if cupsEnumDests(UInt32(CUPS_DEST_FLAGS_NONE), 1000, nil, type, mask, destinationsCallback, &userData) != 1 {
return 0
} else {
return userData.num_dests
}
}
I am not able to get the userData to return the correct value which I am assuming is due to the way I handle the pointers.
Greatly appreciate if I am able to get some advice.
IMHO the best way to work with such C libraries in Swift is to work with them in Objective-C. Nevertheless, the main issue seems to be that you are not writing back changes to userData, that's why you always get your initial value. You need to update it in your callback like this
let userDataPointer = user_data!.assumingMemoryBound(to: my_user_data_t.self)
var userData = userDataPointer.pointee
...
// make some changes to userData
userDataPointer.pointee = userData
return 1
Also there seems to be some differences between your C code and the Swift one, like checking flags with 'flags == CUPS_DEST_FLAGS_REMOVED' which, in general, is incorrect way to check flags, and comparing result of cupsEnumDests with 1 when in the original code you check that result is not 0.

Is it possible to de-duplicate if statements and their body in Rust, perhaps by using macros?

Say we have a large block:
mod module {
pub const fiz: u32 = (1 << 0);
// etc...
}
flag = {
if (var & module::fiz) != 0 { module::fiz }
else if (var & module::foo) != 0 { module::foo }
else if (var & module::bar) != 0 { module::bar }
else if (var & module::baz) != 0 { module::baz }
// .. there could be many more similar checks
};
With simply replacement macro its possible to do:
#define TEST(f) ((var) & (f)) != 0 { f }
Allowing:
flag = {
if TEST(module::fiz)
else if TEST(module::foo)
else if TEST(module::bar)
else if TEST(module::baz)
}
It seems Rust doesn't allow a macro to declare part of an if statement.
I managed to avoid repetition using assignment, but its quite ugly.
flag = {
let f;
if (var & {f = module::fiz; f }) != 0 { f }
else if (var & {f = module::foo; f }) != 0 { f }
else if (var & {f = module::bar; f }) != 0 { f }
else if (var & {f = module::baz; f }) != 0 { f }
};
Does Rust provide some convenient/elegant way to allow repetition in this case?
I don't think flag checking is the important part of this question, the issue is that you may want to repeat content in the check again in the body of an if statement, e.g.:
if (foo && OTHER_EXPRESSION) { do(); something_with(OTHER_EXPRESSION) }
else if (foo && SOME_EXPRESSION) { do(); something_with(SOME_EXPRESSION) }
I think you have an X/Y problem here, so I am going to solve this without using if/else.
What you seem to be doing is checking for the presence of a bit pattern, and prioritise the order in which said patterns are checked for (unclear if it matters, but let's assume it does).
So, let's do this the functional way:
let constants = [fiz, foo, bar, baz];
let flag = constants.iter().filter(|v| var & *v == **v).next();
And it just works, no macro or repetitive stuff.
If you want to use macros, you can write it like this:
mod module {
pub const fiz: u32 = (1 << 0);
pub const foo: u32 = (1 << 1);
pub const bar: u32 = (1 << 2);
pub const baz: u32 = (1 << 3);
}
macro_rules! check_bits {
([$($Constant:expr),*]) => {
|var: u32| {
$(if ($Constant & var) != 0 {
return $Constant;
})*
return 0;
}
}
}
fn main() {
let var = 5;
let checker = check_bits!([module::bar, module::fiz, module::foo, module::baz]);
assert_eq!(checker(var), module::bar);
println!("All OK");
}

EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, sub code=0x0). error while making data structure

I am practicing my array form of data structure with swift.
I made a class "student"
and there are functions like display() and delete()
However, the application is not working.
There is an error message that
EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, sub code=0x0).
I think this error is about "optional" problem.
Here is my code.
class student
{
var studentArray = [[String]?]()
var numberOfStudents : Int = 10;
func display()
{
for (var i = 0; i < numberOfStudents ; i++)
{
print("{");
for (var j = 0; j < 2; j++)
{
print(studentArray[i]![j] + " ");
}
print("}");
}
}
func delete( value : String)
{
var i = 0
for ( i = 0; i < numberOfStudents ; i++)
{
if (value == studentArray[i]![1])
{
break;
}
}
if (i == numberOfStudents - 1 )
{
print("not found");
}
else
{
for (var k = i; k < numberOfStudents - 1 ; k++)
{
studentArray[k]![1] = studentArray[k+1]![1];
studentArray[k]![0] = studentArray[k+1]![0];
}
numberOfStudents--;
}
}
}
var hello = student()
hello.studentArray = [["0","0ee"],["9","9ee", ]]
hello.display() // I have a error at this point
hello.studentArray
Could anyone explain what is about it for me?
There are several mistakes in your code. The actual error is caused by your numberOfStudents variable, which is hard coded to 10, even though the array only contains 2 elements. Use studentArray.count in your for loop, not 10. Then read the Swift manual. You should not be using optionals nor C-style for loops in this example.
Here's how I would do it...
class Student { // Capitalise your classes
// Unnecessary whitespace removed
var studentArray: [[String]] = [] // No need for optionals here
/*
var numberOfStudents : Int = 10; // var is useless & wrong, also no need for semi-colon
*/
func display() {
/* A Swift-ier way to do this is
for student in studentArray {
print("{")
for field in student {
print(field + " ")
}
print("}")
}
However, using indexing:
*/
for i in 0 ..< studentArray.count {
print("{")
for j in 0 ..< studentArray[i].count { // Don't *know* this will be 2
print(studentArray[i][j] + " ") // Don't need semi-colons unless you want to put multiple statements on the same line
}
print("}")
}
}
/* func delete() not used in question, so removed from answer */
}
var hello = Student()
hello.studentArray = [["0","0ee"], ["9","9ee", ]] // Note spurious (but not wrong) comma
hello.display()
hello.studentArray