blob: 40e4fdcf47c74f032bc449098fd948036672e0f2 [file]
// Copyright 2026 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use cxx::UniquePtr;
use std::path::{Path, PathBuf};
#[cxx::bridge]
pub mod ffi {
#[namespace = "base::rust::file_path"]
unsafe extern "C++" {
include!("base/files/file_path.h");
include!("base/files/file_path_rust_shim.h");
#[namespace = "base"]
pub type FilePath;
#[cfg(target_family = "unix")]
fn CreateFilePathFromBytes(bytes: &[u8]) -> UniquePtr<FilePath>;
#[cfg(target_family = "unix")]
fn FilePathToBytes(path: &FilePath) -> &[u8];
#[cfg(target_family = "windows")]
fn CreateFilePathFromWide(wide: &[u16]) -> UniquePtr<FilePath>;
#[cfg(target_family = "windows")]
fn FilePathToWide(path: &FilePath) -> &[u16];
}
}
// SAFETY: `base::FilePath` is an immutable value-like type from Rust's
// perspective (no mutation methods are exposed to Rust). It is a C++
// `base::FilePath` which is thread-safe for concurrent reads. Therefore, it is
// safe to share references across threads (`Sync`) and transfer ownership
// (`Send`).
unsafe impl Send for ffi::FilePath {}
// SAFETY: As above
unsafe impl Sync for ffi::FilePath {}
impl ffi::FilePath {
pub fn from_path(path: &Path) -> UniquePtr<Self> {
#[cfg(unix)]
{
use std::os::unix::ffi::OsStrExt;
ffi::CreateFilePathFromBytes(path.as_os_str().as_bytes())
}
#[cfg(windows)]
{
use std::os::windows::ffi::OsStrExt;
let wide: Vec<u16> = path.as_os_str().encode_wide().collect();
ffi::CreateFilePathFromWide(&wide)
}
#[cfg(not(any(unix, windows)))]
compile_error!("Unsupported platform for base::FilePath FFI");
}
pub fn to_path_buf(&self) -> PathBuf {
#[cfg(unix)]
{
use std::os::unix::ffi::OsStringExt;
let bytes = ffi::FilePathToBytes(self);
PathBuf::from(std::ffi::OsString::from_vec(bytes.to_vec()))
}
#[cfg(windows)]
{
use std::os::windows::ffi::OsStringExt;
let wide = ffi::FilePathToWide(self);
PathBuf::from(std::ffi::OsString::from_wide(wide))
}
#[cfg(not(any(unix, windows)))]
compile_error!("Unsupported platform for base::FilePath FFI");
}
/// Note: `as_os_str` and `as_path` are Unix-only because Unix platforms
/// store paths as bytes, allowing zero-copy references. Windows uses
/// UTF-16 internally, while Rust's `OsStr` uses WTF-8, so any
/// conversion on Windows requires allocation and is not zero-copy.
#[cfg(unix)]
pub fn as_os_str(&self) -> &std::ffi::OsStr {
use std::os::unix::ffi::OsStrExt;
std::ffi::OsStr::from_bytes(ffi::FilePathToBytes(self))
}
#[cfg(unix)]
pub fn as_path(&self) -> &Path {
Path::new(self.as_os_str())
}
}