blob: 9d71876b243f2cc0d4f48d638c2ce31239b37b89 [file]
// Copyright 2026 The Fuchsia Authors
//
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT
use crate::vm::compressor::VmCompressor;
use compression_bindings as bindings;
use core::marker::{PhantomData, PhantomPinned};
use core::pin::Pin;
use pin_init::{PinInit, pin_data};
use zr::{Opaque, pin_init_ffi};
// Note: The upstream C++ `VmCompression` comments and documentation are intentionally not copied
// over yet.
#[pin_data(PinnedDrop)]
#[repr(C)]
pub struct VmCompression {
raw: Opaque<bindings::VmCompression>,
phantom: PhantomData<PhantomPinned>,
}
zr::unsafe_pinned_drop_ffi!(VmCompression, bindings::cpp_vmcompression_destroy);
impl VmCompression {
/// Domain-specific conversion: returns raw pointer for `VmCompression`.
pub fn as_raw(&self) -> *mut bindings::VmCompression {
self.raw.get()
}
}
/// An RAII wrapper around holding a locked reference to a `VmCompressor`.
///
/// Acquiring a compressor may block until one becomes available, and callers should be prepared
/// for extended wait times. The guard must not outlive the `VmCompression` it was acquired from.
#[pin_data(PinnedDrop)]
#[repr(transparent)]
pub struct CompressorGuard<'a> {
opaque: Opaque<bindings::VmCompression_CompressorGuard>,
phantom: PhantomData<&'a VmCompression>,
// The C++ guard owns a held `Guard<Mutex>`, which may only be relocated by its move
// constructor. Marking this field `#[pin]` is what makes the type `!Unpin`, and so prevents
// safe code from moving it out of the `Pin` it is constructed in.
#[pin]
_pin: PhantomPinned,
}
zr::unsafe_pinned_drop_ffi!(
CompressorGuard<'_>,
bindings::cpp_vmcompression_compressor_guard_destroy
);
impl<'a> CompressorGuard<'a> {
/// Retrieves a compressor from `compression`, wrapped in an RAII guard. Once the compressor is
/// finished with it can be dropped, which will release it for reuse.
pub fn new(compression: &'a VmCompression) -> impl PinInit<Self> {
pin_init_ffi!(bindings::cpp_vmcompression_acquire_compressor, compression.as_raw())
}
/// Returns a reference to the guarded `VmCompressor`.
pub fn get(self: Pin<&mut Self>) -> &VmCompressor {
// SAFETY: Nothing is moved out of the returned reference; it is only used to read
// `opaque`'s address.
let this = unsafe { self.get_unchecked_mut() };
// SAFETY: `this.opaque.get()` points to a live `CompressorGuard`.
let raw = unsafe { bindings::cpp_vmcompression_compressor_guard_get(this.opaque.get()) };
// SAFETY: The shim returns the address of a reference, so it is never null, and
// `VmCompressor` is a `repr(C)` wrapper whose only field is the corresponding opaque
// binding type. The compressor is owned by the guard, so it stays live for as long as
// `this` is borrowed.
unsafe { &*raw.cast::<VmCompressor>() }
}
}
impl fbl::HasRefCount for VmCompression {
fn ref_count(&self) -> &fbl::RefCounted {
// SAFETY: `cpp_vmcompression_get_ref_counted` returns a valid pointer to the C++
// `fbl::RefCounted` subobject of `VmCompression`.
unsafe {
&*(bindings::cpp_vmcompression_get_ref_counted(self.as_raw()) as *const fbl::RefCounted)
}
}
}
unsafe impl fbl::Recyclable for VmCompression {
unsafe fn recycle(ptr: core::ptr::NonNull<Self>) {
unsafe { bindings::cpp_vmcompression_free(ptr.as_ptr() as *mut bindings::VmCompression) }
}
}