WebRTC is adopting Rust to advance memory safety. Rust targets and build infrastructure have been integrated into the repository and are enabled by default.
Currently there are few Rust component integrated into tests, but not production code.
As a next step we plan to integrate a small Rust component into production code, but keep a c++ fallback.
Rust support is controlled by the GN build argument rtc_rust in webrtc.gni:
# Enables or disables Rust targets in WebRTC. rtc_rust = true
C++ code can check if Rust is enabled by checking WEBRTC_WITHOUT_RUST define.
We plan to eventually remove the rtc_rust build flag and WEBRTC_WITHOUT_RUST define and require all downstream builds to provide a working Rust toolchain.
rtc_rust_library: Defines a Rust static library.rtc_rust_cxx_bridge: Defines a single-source C++/Rust FFI bridge using the CXX crate.rtc_rust_unittest: Defines a single Rust unit test binary.rtc_rust_test_suite: Aggregates multiple Rust unit test targets into a test suite group.With few exceptions, WebRTC follows Chromium Rust Style guide, which in turn follows Rust Style Guide and Rust API Guidelines.
webrtc::import! { // Crates can be imported using their target name (e.g. `time_delta_rs`): "//api/unit:time_delta_rs"; // Target names can be overridden for brevity: "//modules/rtp_rtcp:corruption_detection_extension" as cde; }
See Rust Book for the guidance.
Support for Chromium's test framework or Googles test framework is currently not implemented.
Interoperability between C++ and Rust is handled through the CXX crate.
We plan to switch to Crubit when its support will be implemented in more environments, in particular when it will be fully supported by chromium infrastructure.
FFI bindings are declared in Rust source files using #[cxx::bridge]. Use C++ namespace webrtc for all bindings. Declare bindings in Rust mod ffi.
Examples:
// bindings to call C++ from Rust #[cxx::bridge(namespace = "webrtc")] mod ffi { unsafe extern "C++" { include!("path/to/a_cpp_library.h"); fn CppFunction(value: i32) -> i64; } } pub fn cpp_function(value: i32) -> i64 { ffi::CppFunction(value) }
// bindings to call Rust from C++ webrtc::import! { "//path/to/rust:a_rust_library"; } use a_rust_library::rust_function; #[cxx::bridge(namespace = "webrtc")] mod ffi { extern "Rust" { fn rust_function(value: i64) -> u64; } }
import("../../webrtc.gni") rtc_library("cpp_only_library") { sources = [ "cpp_only_library.cc", "cpp_only_library.h", ] } if (rtc_rust) { rtc_rust_cxx_bridge("call_cpp_from_rust_cxx") { allow_unsafe = true source = "call_cpp_from_rust_cxx.rs" deps = [ ":cpp_only_library", "//build/rust:cxx_rustdeps", ] } rtc_rust_library("my_rust_feature") { crate_root = "my_rust_feature.rs" sources = [ "my_rust_feature.rs" ] deps = [ ":call_cpp_from_rust_cxx", ] } rtc_rust_unittest("my_rust_feature_test") { crate_root = "my_rust_feature.rs" sources = [ "my_rust_feature.rs" ] deps = [ ":call_cpp_from_rust_cxx", ] } rtc_rust_cxx_bridge("call_rust_from_cpp_cxx") { allow_unsafe = true source = "call_rust_from_cpp_cxx.rs" deps = [ ":my_rust_feature", "//build/rust:cxx_rustdeps", ] } } rtc_library("cpp_maybe_use_rust") { sources = [ "cpp_maybe_use_rust.cc" ] deps = [...] if (rtc_rust) { deps += [":call_rust_from_cpp_cxx"] } }
// cpp_maybe_use_rust.cc #ifndef WEBRTC_WITHOUT_RUST #include "call_rust_from_cpp_cxx.rs.h" #endif ... uint64_t MaybeUseRust(int64_t value) { #ifdef WEBRTC_WITHOUT_RUST return CallCppFallback(value); #else return rust_function(value); #endif }