foreign_vec 0.1.0

Unofficial implementation of Apache Arrow spec in safe Rust
Documentation
This library offers [`ForeignVec`], a zero-cost abstraction to store either [`Vec<T>`]
or an immutable region aligned with `T` allocated by an external allocator.

The primary use-case of this library is when you have an in-memory representation
in both Rust and other languages and you have a specification to share
(immutable) vectors across language boundaries at zero cost, via FFI.

In this scenario, you may want to still offer all the benefits of Rust's `Vec`
when it comes to mutable access, while providing a read-only access when the
data came from a foreign interface. In other words, given

* an in-memory format
* an FFI specification to share immutable memory regions at zero cost at language
  boundaries

then, [`ForeignVec`] offers an interface to

* allow zero-cost immutable access via `core::ops::Deref<T>` to `Vec<T>` or
  the foreign vector
* allow access to `&mut Vec<T>` when it is allocated by Rust

The crucial point here is "zero-cost immutable access". The usual idiom
here is to have an `enum` with two variants, `Native(Vec<T>)` and another.
However, such enum incurs a significant (`+50%`) cost when deferring the enum
into `&[T]`.

The complete test:

```rust
use foreign_vec::ForeignVec;

// say that we have a foreign struct allocated by an external allocator (e.g. C++)
// owning an immutable memory region
#[repr(C)]
struct Foreign {
    ptr: *const i32,
    length: usize,
    // this is usually created at the FFI boundary; `capacity` is usually "hidden" in that
    // it could contain a C++ `shared_ptr` or something else describing the region
    // "on the other side".
    capacity: usize,
}

// whose drop calls an external function that deallocates the region
impl Drop for Foreign {
    fn drop(&mut self) {
        // mocking an external deallocation
        unsafe { Vec::from_raw_parts(self.ptr as *mut i32, self.length, self.capacity) };
    }
}

// The type that we use on the library uses `foreign_vec`
// this could be a generic over `T` when the in-memory format supports multiple types.
type MyForeignVec = ForeignVec<Foreign, i32>;

#[test]
fn test_vec() {
    // we can use it with `Vec`:
    let expected: &[i32] = &[1, 2];

    // when we have a vector, we can use `.into()`
    let vec = expected.to_vec();
    let mut vec: MyForeignVec = vec.into();

    // deref works as expected
    assert_eq!(&*vec, expected);

    // debug works as expected
    assert_eq!(format!("{:?}", vec), "[1, 2]");

    // you can retrieve a mut vec (since it is allocated by Rust)
    assert_eq!(vec.get_vec(), Some(&mut vec![1, 2]));

    // this calls `Vec::drop`, as usual
    drop(vec)
}

// this is just `Vec::into_raw_parts`, which is only available in unstable channels
fn into_raw_parts<T>(vec: Vec<T>) -> (*mut T, usize, usize) {
    let r = (vec.as_ptr() as *mut T, vec.len(), vec.capacity());
    std::mem::forget(vec);
    r
}

#[test]
fn test_foreign() {
    // on an externally allocated pointer (here from Rust, but a foreign call would do the same)
    let expected: &[i32] = &[1, 2];

    let a = expected.to_vec();
    let (ptr, length, capacity) = into_raw_parts(a);
    // this is usually created at the FFI boundary; `capacity` is usually "hidden" in that
    // it could contain a C++ `shared_ptr` instead.
    let a = Foreign {
        ptr,
        length,
        capacity,
    };

    // create a `MyForeignVec` from a foreign that implements `Deref`.
    let mut vec = unsafe { MyForeignVec::from_foreign(a.ptr, a.length, a) };
    assert_eq!(&*vec, expected);
    assert_eq!(vec.get_vec(), None);

    // this calls `Foreign::drop`, which calls the foreign function
    drop(vec);
}

```