#cell #loops #async #borrow #from-fn #no-alloc

no-std loopcell

用于多路径访问的 cell,每次只能按顺序使用一个。

1 个稳定版本

新版本 1.0.0 2024 年 8 月 16 日

770Rust 模式

MPL-2.0 许可证

29KB
451

loopcell

专为读-改-写风格的循环设计的 cell 类型,避免手动写入步骤。

在具有多个输入流复杂事件处理服务中很有用,特别是当你在下一次迭代之前丢弃产生的值时,它非常适合迭代器范式。在许多方面,它可以作为一个“运行时版本”的借用迭代器。

它还与 qcellghost_cell 和类似包很好地结合使用,如果你使用 LoopCellLoopSyncCell 作为所有权控制类型。

快速示例

这是一个快速示例,说明了如何使用 LoopCell 创建一个迭代器,该迭代器重用共享缓冲区以处理事件。您可以使用 LoopSyncCell 做到类似的事情,但在需要跨线程转移访问的情况下(在实现 futures 时很常见),它将工作得更好。

use std::ops::{Deref, DerefMut};
pub struct Event {
    /// If `true`, then no more events should be processed after this.
    pub last: bool
} 

impl Event {
    /// Dummy function that writes to the buffer.
    pub fn serialize_into(self, buffer: &mut Vec<u8>) {
        buffer.extend(b"DUMMY VALUE\n");
    }
}

/// This illustrates the way this can be used as a pseudo-runtime-lending-iterator.
/// While this specific case could be implemented without the loopcell, in more complex
/// cases like having multiple iterators that all reuse the buffer or provide values that
/// reference the buffer, this is not possible because only one would be able to hold a
/// mutable reference at a time
fn write_events(events: impl Iterator<Item = Event>, mut process_event_bytes: impl FnMut(&mut [u8])) {
    let buffer = loopcell::LoopCell::new(Vec::<u8>::with_capacity(8192));
    // Iterator that returns `Some` of an access to the buffer, while it's refilled.
    let buffer_iter = core::iter::from_fn(|| buffer.access()).fuse();
    for (mut buffer_handle, next_event) in buffer_iter.zip(events) {
        let is_last_event = next_event.last; 
        {
            let mut buffer_access = WipeOnDrop::from(buffer_handle.as_mut());
            next_event.serialize_into(&mut buffer_access);
            process_event_bytes(&mut buffer_access);
        }
        if is_last_event {
            buffer_handle.consume();
        }
    }
}

fn main() {
    // Illustrate the way the loopcell enables iteration using conditional consumption of
    // the handles. 
    let mut counter = 0; 
    let mut increment_counter = |_bytes: &mut _| { counter += 1; };
    let events = [false, false, false, true].map(|last| Event { last });
    write_events(events.into_iter(), &mut increment_counter);
    assert_eq!(counter, 4);
}

/// Implementation detail that wipes a buffer with `clear()` on drop, but inherently preserves capacity.
pub struct WipeOnDrop<'b>(&'b mut Vec<u8>);

impl <'b> From<&'b mut Vec<u8>> for WipeOnDrop<'b> {
    fn from(v: &'b mut Vec<u8>) -> Self {
        Self(v)
    }
}

impl <'b> Deref for WipeOnDrop<'b> {
    type Target = Vec<u8>;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl <'b> DerefMut for WipeOnDrop<'b> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.0
    }
}

impl <'b> Drop for WipeOnDrop<'b> {
    fn drop(&mut self) {
        self.0.clear()
    }
}


依赖项

~33KB