Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Porting a C++ Program to Rust: Of reinterpret_cast, Structs and Bluetooth

I have a C++ program that statically links against libbluetooth/BlueZ, and I would like to port it to Rust as an exercise.

One particularly ugly bit of the C++ code reads data from a UNIX file descriptor via read(), and the resulting buffer is then cast to a struct via reinterpret_cast. Unfortunately, I have no idea how to achieve a similar thing in Rust. The idea is to capture instances of le_advertising_info from libbluetooth.

C++11 Code:

std::uint8_t buf [HCI_MAX_EVENT_SIZE];
evt_le_meta_event* evt;
le_advertising_info* info;

if (read(_deviceFD, buf, sizeof (buf)) >= HCI_EVENT_HDR_SIZE) {
    evt = reinterpret_cast<evt_le_meta_event*>(buf + HCI_EVENT_HDR_SIZE + 1);
    if (evt != nullptr && evt->subevent == EVT_LE_ADVERTISING_REPORT) {
        void* offset = evt->data + 1;
        for (auto i = 0; i < evt->data [0]; i++) {
            info = reinterpret_cast<le_advertising_info*>(offset);
            if (info != nullptr) {
                if (isBeacon(*info)) {
                    writeLogEntry(*info);
                }
                offset = info->data + info->length + 2;
            }
        }
    }
}

Some pointers on how to port this bit to Rust (in an elegant and safe fashion) are greatly appreciated.

like image 994
E Y Avatar asked Mar 09 '23 19:03

E Y


1 Answers

In Rust you can use the unsafe std::mem::transmute function to cast from one type to another as long as they have the same size.

In the specific case where you are only casting from one pointer to another, though, this is not even required: you can just use as.

struct Hello { a: i32 }
struct World { b: i32 }

fn main() {
    let h = Hello { a: 42 };
    let w = &h as *const Hello as *const World;
    let w: &World = unsafe { &*w };
    println!("{}", w.b);
}

Note that you need the unsafe keyword to go from pointer to reference. Rust allows you to manipulate pointers at leisure, however dereferencing a pointer is potentially unsafe (if said pointer is pointing where it should not).

Since this last step is "gated", converting from reference to pointer, or from one pointer type to another, is safe.

Unlike C or C++, there is no "strict aliasing" rule in Rust, so the above is perfectly safe and compliant.

like image 114
Matthieu M. Avatar answered Apr 20 '23 00:04

Matthieu M.