[][src]Crate pin_cursor

A simple !Unpin I/O backend for async-std, designed for use in tests.

This crate provides the PinCursor struct which wraps around async_std::io::Cursor but is explicitly not Unpin. It is a little building block to help write tests where you want to ensure that your own asynchronous IO code behaves correctly when reading from or writing to something that is definitely !Unpin.

  • It can be backed by any Unpin data buffer that can be slotted into async_std::io::Cursor. Usually Vec<u8> or &mut [u8] (e. g. from an array) are used.
  • It implements async_std::io::{Read, Write, Seek}, so you can poll these traits' methods in your own futures.
  • At the same time, it provides several high-level methods through which you can manipulate the PinCursor in a simple async {} block.


use pin_cursor::PinCursor;
use async_std::io::{prelude::*, Cursor};
use std::io::SeekFrom;
use std::pin::Pin;

// Construct a async_std::io::Cursor however you like...
let mut data: Vec<u8> = Vec::new();
let cursor = Cursor::new(&mut data);
// ... then wrap it in PinCursor and a pinned pointer, thus losing the Unpin privileges.
let mut cursor: Pin<Box<PinCursor<_>>> = Box::pin(PinCursor::wrap(cursor));
// Note that we have to make an owning pointer first -
// making a Pin<&mut PinCursor<_>> directly is impossible!
// (There is a more complex way to allocate on stack - see the features section.)

// Methods of PinCursor mostly return futures and are designed for use in async contexts.
async {
    // You can write!
    assert_eq!(cursor.as_mut().write(&[1u8, 2u8, 3u8]).await.unwrap(), 3);
    // You can seek!
    assert_eq!(cursor.position(), 3);
    assert_eq!(cursor.as_mut().seek(SeekFrom::Start(1)).await.unwrap(), 1);
    assert_eq!(cursor.position(), 1);
    // You can read!
    let mut buf = [0u8; 1];
    assert_eq!(cursor.as_mut().read(buf.as_mut()).await.unwrap(), 1);
    assert_eq!(buf[0], 2);

    // There's also this way of seeking that doesn't involve futures.
    assert_eq!(cursor.as_mut().read(buf.as_mut()).await.unwrap(), 1);
    assert_eq!(buf[0], 1);


The optional feature stackpin enables integration with stackpin, a crate that provides a way to allocate !Unpin structures on stack.

This example is not tested
use stackpin::stack_let;

let mut data: Vec<u8> = vec![1, 2];
stack_let!(mut cursor : PinCursor<_> = Cursor::new(&mut data));
let cursor_ptr: Pin<&mut PinCursor<_>> = Pin::as_mut(&mut cursor);

Now you have a correctly pinned PinCursor that's allocated on stack instead of in a box.