5

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.

Matthieu M.
  • 287,565
  • 48
  • 449
  • 722
E Y
  • 281
  • 2
  • 11

1 Answers1

9

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.

Matthieu M.
  • 287,565
  • 48
  • 449
  • 722
  • Thanks for the response! This is very close to what I was looking for. I'll update the question to detail the problem a bit better though. – E Y Feb 28 '17 at 15:05
  • 1
    @EleanoreY: Please don't! (I reverted your edit). An edit should be about clarifying the question, but your edit was about a completely different issue altogether. If you have a different problem, please ask a different question *after* reducing the new problem to a [MCVE]. – Matthieu M. Feb 28 '17 at 15:28
  • @EleanoreY: No problem :) Looking forward to your next question. – Matthieu M. Feb 28 '17 at 15:50