// Copyright 2024, The Android Open Source Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. use super::shared::Shared; use core::{ mem::{swap, take}, ops::{Deref, DerefMut}, }; use gbl_async::yield_now; /// Provides interfaces for allocating and deallocating buffers. pub trait BufferPool { /// The type that can be dereferenced into a buffer. type Buffer: DerefMut; /// Allocates a buffer. /// /// * Returns Some(_) on success. /// * Returns None if buffer is not available. fn allocate(&mut self) -> Option; /// Deallocates a buffer. fn deallocate(&mut self, buf: Self::Buffer); } // Implements for all types of fixed size preallocated buffers, including `&mut [&mut [u8]]`, // `Vec`, `&mut [Vec]` and `Vec<&mut [u8]>`. impl BufferPool for T where B: DerefMut + Default, // Can be `&mut [u8]`, `Vec` T: DerefMut, // Can be `&mut [B]`, `Vec` { type Buffer = B; fn allocate(&mut self) -> Option { self.iter_mut().find_map(|v| (v.len() > 0).then_some(take(v))) } fn deallocate(&mut self, mut buf: B) { swap(&mut buf, self.iter_mut().find(|v| v.len() == 0).unwrap()); } } impl Shared { // Try allocate a [ScopedBuffer] pub(crate) fn allocate(&self) -> Option> { self.borrow_mut().allocate().map(|v| ScopedBuffer { buf: Some(v), pool: self }) } // Allocates a [ScopedBuffer] and waits until succeed. pub(crate) async fn allocate_async(&self) -> ScopedBuffer { loop { match self.allocate() { Some(v) => return v, _ => yield_now().await, } } } } /// Represents a scoped buffer allocated by `BufferPool`. pub(crate) struct ScopedBuffer<'a, T: BufferPool> { buf: Option, pool: &'a Shared, } impl Drop for ScopedBuffer<'_, T> { fn drop(&mut self) { self.pool.borrow_mut().deallocate(self.buf.take().unwrap()) } } impl Deref for ScopedBuffer<'_, T> { type Target = [u8]; fn deref(&self) -> &Self::Target { self.buf.as_ref().unwrap() } } impl DerefMut for ScopedBuffer<'_, T> { fn deref_mut(&mut self) -> &mut Self::Target { self.buf.as_mut().unwrap() } }