_ffi_rustc/
lib.rs

1// Copyright 2022 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use fuchsia_async as fasync;
6use futures::channel::mpsc as async_mpsc;
7use futures::StreamExt;
8use std::sync::mpsc as sync_mpsc;
9use wayland_bridge::dispatcher::WaylandDispatcher;
10use zx::{self as zx, HandleBased};
11
12pub enum WaylandCommand {
13    PushClient(zx::Channel),
14}
15
16#[repr(C)]
17#[allow(non_camel_case_types)]
18pub struct wayland_server_handle_t {
19    pub sender: async_mpsc::UnboundedSender<WaylandCommand>,
20}
21
22fn start_wayland_server() -> Result<(fasync::LocalExecutor, WaylandDispatcher), zx::Status> {
23    let mut executor = fasync::LocalExecutor::new();
24    let mut dispatcher = WaylandDispatcher::new().map_err(|e| {
25        log::error!("Failed to create wayland dispatcher: {}", e);
26        zx::Status::INTERNAL
27    })?;
28    // Try to get display properties before serving.
29    let scenic = dispatcher.display.scenic().clone();
30    match executor.run_singlethreaded(async { scenic.get_display_info().await }) {
31        Ok(display_info) => dispatcher.display.set_display_info(&display_info),
32        Err(e) => eprintln!("get_display_info error: {:?}", e),
33    }
34    Ok((executor, dispatcher))
35}
36
37#[no_mangle]
38#[allow(clippy::not_unsafe_ptr_arg_deref)]
39pub extern "C" fn wayland_server_create(
40    out: *mut *mut wayland_server_handle_t,
41) -> zx::sys::zx_status_t {
42    let (sender, mut receiver) = async_mpsc::unbounded::<WaylandCommand>();
43    let (result_sender, result_receiver) = sync_mpsc::sync_channel::<zx::sys::zx_status_t>(0);
44    std::thread::spawn(move || {
45        let (mut executor, dispatcher) = match start_wayland_server() {
46            Ok(result) => {
47                result_sender.send(zx::sys::ZX_OK).unwrap();
48                result
49            }
50            Err(status) => {
51                result_sender.send(status.into_raw()).unwrap();
52                return;
53            }
54        };
55
56        executor.run_singlethreaded(async move {
57            while let Some(WaylandCommand::PushClient(channel)) = receiver.next().await {
58                dispatcher
59                    .display
60                    .clone()
61                    .spawn_new_client(fasync::Channel::from_channel(channel), false);
62            }
63        });
64    });
65
66    let result = match result_receiver.recv() {
67        Ok(status) => status,
68        Err(_) => zx::sys::ZX_ERR_INTERNAL,
69    };
70
71    if result == zx::sys::ZX_OK {
72        // Allocate the type we provide to the caller on the heap. This will be owned by the client
73        // so we leak the pointer here.
74        let ptr = Box::leak(Box::new(wayland_server_handle_t { sender }));
75
76        unsafe { *out = ptr };
77    }
78    result
79}
80
81#[no_mangle]
82#[allow(clippy::not_unsafe_ptr_arg_deref)]
83pub extern "C" fn wayland_server_push_client(
84    server_handle: *mut wayland_server_handle_t,
85    channel: zx::sys::zx_handle_t,
86) {
87    let handle = unsafe { zx::Handle::from_raw(channel) };
88    // Unwrap here since this will only fail if we're provided with a null pointer, which is not
89    // something we support.
90    let server = unsafe { server_handle.as_mut().unwrap() };
91    // Unwrap here since the only failure mode is if this is called after `wayland_server_destroy`,
92    // which is not supported.
93    server
94        .sender
95        .unbounded_send(WaylandCommand::PushClient(zx::Channel::from_handle(handle)))
96        .unwrap();
97}
98
99#[no_mangle]
100#[allow(clippy::not_unsafe_ptr_arg_deref)]
101pub extern "C" fn wayland_server_destroy(server_handle: *mut wayland_server_handle_t) {
102    unsafe {
103        // Drop the boxed pointer.
104        let _ = Box::from_raw(server_handle);
105    }
106}