Skip to content

Commit

Permalink
crate-ify Buf as a library with CSlice and CMutSlice abstractions
Browse files Browse the repository at this point in the history
  • Loading branch information
Dave Herman committed Apr 5, 2016
1 parent 48bfc0c commit 81d59e2
Show file tree
Hide file tree
Showing 9 changed files with 216 additions and 79 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ license = "MIT/Apache2"
exclude = ["neon.jpg"]

[dependencies]
cslice = { version = "=0.1.0", path = "crates/cslice" }
neon-sys = { version = "=0.1.8", path = "crates/neon-sys" }
200 changes: 200 additions & 0 deletions crates/cslice/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
//! A library of _C-slices_: slices with a stable ABI for interfacing with C.
//!
//! This library provides two types, `CSlice` and `CMutSlice`, for communicating
//! with C about Rust slices or foreign slice-like data structures. Both types
//! have a stable ABI consisting of exactly two pointer-sized words:
//!
//! ```c
//! struct {
//! void *base;
//! size_t len;
//! }
//! ```
//!
//! C-slices and Rust slices are interchangeable, with conversion methods in both
//! directions.
//!
//! This makes it possible to construct slices from foreign code, as well as to
//! communicate Rust slices to foreign code conveniently.

use std::{ptr, slice};
use std::marker::PhantomData;
use std::ops::{Index, IndexMut};

/// An immutable slice, equivalent to `&'a T`.
///
/// A `CSlice` can be constructed from a corresponding Rust slice via the `AsCSlice` trait.
///
/// A Rust slice can be constructed from a corresponding `CSlice` via `as_ref`.
#[repr(C)]
#[derive(Clone, Copy)]
pub struct CSlice<'a, T> {
base: *const T,
len: usize,
marker: PhantomData<&'a ()>
}

impl<'a, T> CSlice<'a, T> {
/// Create a `CSlice` from raw data.
///
/// # Safety
///
/// The region of memory from `base` (inclusive) to `base + len * sizeof<T>`
/// (exclusive) must be valid for the duration of lifetime `'a`.
pub unsafe fn new(base: *const T, len: usize) -> Self {
assert!(base != ptr::null());
CSlice {
base: base,
len: len,
marker: PhantomData
}
}

/// Produces a raw pointer to the slice's buffer.
pub fn as_ptr(&self) -> *const T {
self.base
}

/// Returns the number of elements in the slice.
pub fn len(&self) -> usize {
self.len
}
}

impl<'a, T> AsRef<[T]> for CSlice<'a, T> {
fn as_ref(&self) -> &[T] {
unsafe {
slice::from_raw_parts(self.base, self.len)
}
}
}

/// A mutable slice, equivalent to `&'a mut T`.
///
/// A `CMutSlice` can be constructed from a corresponding Rust slice via the `AsCMutSlice` trait.
///
/// A Rust slice can be constructed from a corresponding `CMutSlice` via `as_mut`.
#[repr(C)]
#[derive(Clone, Copy)]
pub struct CMutSlice<'a, T> {
base: *mut T,
len: usize,
marker: PhantomData<&'a ()>
}

impl<'a, T> CMutSlice<'a, T> {
/// Create a `CSlice` from raw data.
///
/// # Safety
///
/// The region of memory from `base` (inclusive) to `base + len * sizeof<T>`
/// (exclusive) must be valid for the duration of lifetime `'a`.
pub unsafe fn new(base: *mut T, len: usize) -> Self {
assert!(base != ptr::null_mut());
CMutSlice {
base: base,
len: len,
marker: PhantomData
}
}

/// Produces a raw pointer to the slice's buffer.
pub fn as_ptr(&self) -> *const T {
self.base
}

/// Produces a raw pointer to the slice's buffer.
pub fn as_mut_ptr(&mut self) -> *mut T {
self.base
}

/// Returns the number of elements in the slice.
pub fn len(&self) -> usize {
self.len
}
}

impl<'a, T> AsRef<[T]> for CMutSlice<'a, T> {
fn as_ref(&self) -> &[T] {
unsafe {
slice::from_raw_parts(self.base, self.len)
}
}
}

impl<'a, T> AsMut<[T]> for CMutSlice<'a, T> {
fn as_mut(&mut self) -> &mut [T] {
unsafe {
slice::from_raw_parts_mut(self.base, self.len)
}
}
}

unsafe impl<'a, T> Sync for CSlice<'a, T> { }

unsafe impl<'a, T> Sync for CMutSlice<'a, T> { }


impl<'a, T> Index<usize> for CSlice<'a, T> {
type Output = T;

fn index(&self, i: usize) -> &T {
self.as_ref().index(i)
}
}

impl<'a, T> Index<usize> for CMutSlice<'a, T> {
type Output = T;

fn index(&self, i: usize) -> &T {
self.as_ref().index(i)
}
}

impl<'a, T> IndexMut<usize> for CMutSlice<'a, T> {
fn index_mut(&mut self, i: usize) -> &mut T {
self.as_mut().index_mut(i)
}
}

/// A cheap conversion to a `CSlice`.
pub trait AsCSlice<'a, T> {
/// Performs the conversion.
fn as_c_slice(&'a self) -> CSlice<'a, T>;
}

/// A cheap conversion to a `CMutSlice`.
pub trait AsCMutSlice<'a, T> {
/// Performs the conversion.
fn as_c_mut_slice(&'a mut self) -> CMutSlice<'a, T>;
}

impl<'a> AsCSlice<'a, u8> for str {
fn as_c_slice(&'a self) -> CSlice<'a, u8> {
CSlice {
base: self.as_ptr(),
len: self.len(),
marker: PhantomData
}
}
}

impl<'a, T> AsCSlice<'a, T> for [T] {
fn as_c_slice(&'a self) -> CSlice<'a, T> {
CSlice {
base: self.as_ptr(),
len: self.len(),
marker: PhantomData
}
}
}

impl<'a, T> AsCMutSlice<'a, T> for [T] {
fn as_c_mut_slice(&'a mut self) -> CMutSlice<'a, T> {
CMutSlice {
base: self.as_mut_ptr(),
len: self.len(),
marker: PhantomData
}
}
}
3 changes: 3 additions & 0 deletions crates/neon-sys/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,8 @@ links = "neon"
# this script builds libneon.a
build = "build.rs"

[dependencies]
cslice = { version = "=0.1.0", path = "../cslice" }

[build-dependencies]
gcc = "0.3"
71 changes: 0 additions & 71 deletions crates/neon-sys/src/buf.rs

This file was deleted.

6 changes: 4 additions & 2 deletions crates/neon-sys/src/buffer.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
use raw::Local;
use buf::Buf;
use cslice::CMutSlice;

// Suppress a spurious rustc warning about the use of CMutSlice.
#[allow(improper_ctypes)]
extern "system" {

#[link_name = "NeonSys_Buffer_New"]
pub fn new(out: &mut Local, size: u32) -> bool;

#[link_name = "NeonSys_Buffer_Data"]
pub fn data<'a, 'b>(out: &'a mut Buf<'b>, obj: Local);
pub fn data<'a, 'b>(out: &'a mut CMutSlice<'b, u8>, obj: Local);

}
3 changes: 2 additions & 1 deletion crates/neon-sys/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
extern crate cslice;

pub mod raw;
pub mod buf;
pub mod call;
pub mod scope;
pub mod object;
Expand Down
6 changes: 3 additions & 3 deletions src/internal/js/binary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ use internal::js::{Value, ValueInternal, Object, build};
use internal::mem::{Handle, Managed};
use internal::vm::{Lock, LockState};
use scope::Scope;
use cslice::CMutSlice;
use neon_sys;
use neon_sys::raw;
use neon_sys::buf::Buf;

#[repr(C)]
#[derive(Clone, Copy)]
Expand Down Expand Up @@ -38,12 +38,12 @@ impl Object for JsBuffer { }
// tighten the lifetime of the exposed internals not to outlive the
// lock.
impl<'a> Lock for Handle<'a, JsBuffer> {
type Internals = Buf<'a>;
type Internals = CMutSlice<'a, u8>;

unsafe fn expose(self, state: &mut LockState) -> Self::Internals {
let mut result = mem::uninitialized();
neon_sys::buffer::data(&mut result, self.to_raw());
state.use_buffer(&result);
state.use_buffer(result);
result
}
}
4 changes: 2 additions & 2 deletions src/internal/vm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ use std::any::TypeId;
use std::marker::PhantomData;
use std::collections::{HashSet, HashMap};
use std::os::raw::c_void;
use cslice::CMutSlice;
use neon_sys;
use neon_sys::raw;
use neon_sys::buf::Buf;
use internal::scope::{Scope, RootScope, RootScopeInternal};
use internal::js::{JsValue, Value, Object, JsObject, JsFunction};
use internal::js::class::ClassMetadata;
Expand Down Expand Up @@ -286,7 +286,7 @@ pub struct LockState {
}

impl LockState {
pub fn use_buffer(&mut self, buf: &Buf) {
pub fn use_buffer(&mut self, buf: CMutSlice<u8>) {
let p = buf.as_ptr() as usize;
if !self.buffers.insert(p) {
panic!("attempt to lock heap with duplicate buffers (0x{:x})", p);
Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! The `neon` crate provides the entire [Neon](http://neon.rustbridge.io) API.

extern crate neon_sys;
extern crate cslice;

mod internal;
pub mod mem;
Expand Down

0 comments on commit 81d59e2

Please sign in to comment.