blob: 05cf025ce3b7a131f9a4f880524d65915d86615b [file] [log] [blame]
// Copyright 2018 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::marker::PhantomData;
use std::os::raw::{c_char, c_uint, c_void};
use std::sync::Arc;
use std::{mem, ops, ptr, slice};
use sys;
/// Blobs wrap a chunk of binary data to handle lifecycle management of data
/// while it is passed between client and HarfBuzz.
///
/// Blobs are primarily used to create font faces, but also to access font face
/// tables, as well as pass around other binary data.
pub struct Blob<'a> {
raw: *mut sys::hb_blob_t,
phantom: PhantomData<&'a [u8]>,
}
impl<'a> Blob<'a> {
/// Create a new read-only blob.
///
/// The data is not copied, so it must outlive the
/// `Blob`.
///
/// ```
/// # use harfbuzz::Blob;
/// let data = vec![1; 256];
/// let blob = Blob::new_read_only(&data);
/// assert_eq!(blob.len(), 256);
/// assert!(!blob.is_empty());
/// ```
pub fn new_read_only(data: &'a [u8]) -> Blob<'a> {
assert!(data.len() <= c_uint::max_value() as usize);
unsafe {
Blob::from_raw(sys::hb_blob_create(
data.as_ptr() as *const c_char,
data.len() as c_uint,
sys::HB_MEMORY_MODE_READONLY,
ptr::null_mut(), // user data
None, // destroy callback
))
}
}
/// Create a blob wrapping an `Arc<Vec<u8>>`.
///
/// This method allows creation of a blob without copying, where the
/// data may be shared by Rust code and the blob. The `Vec` is freed
/// when all references are dropped.
///
/// ```
/// # use std::sync::Arc;
/// # use harfbuzz::Blob;
/// let data = vec![1; 256];
/// let blob = Blob::new_from_arc_vec(Arc::new(data));
/// assert_eq!(blob.len(), 256);
/// assert!(!blob.is_empty());
/// ```
pub fn new_from_arc_vec(data: Arc<Vec<u8>>) -> Blob<'static> {
let len = data.len();
assert!(len <= c_uint::max_value() as usize);
unsafe {
let data_ptr = data.as_ptr();
let ptr = Arc::into_raw(data);
// This has type hb_destroy_func_t
unsafe extern "C" fn arc_vec_blob_destroy(user_data: *mut c_void) {
drop(Arc::from_raw(user_data as *const Vec<u8>))
}
let hb_blob = sys::hb_blob_create(
data_ptr as *const c_char,
len as c_uint,
sys::HB_MEMORY_MODE_READONLY,
ptr as *mut c_void,
Some(arc_vec_blob_destroy),
);
Blob::from_raw(hb_blob)
}
}
/// Construct a `Blob` from a raw pointer. Takes ownership of the blob.
pub unsafe fn from_raw(raw: *mut sys::hb_blob_t) -> Self {
Blob {
raw,
phantom: PhantomData,
}
}
/// Returns the size of the blob in bytes.
pub fn len(&self) -> usize {
unsafe { sys::hb_blob_get_length(self.raw) as usize }
}
/// Returns true if the length is zero.
pub fn is_empty(&self) -> bool {
self.len() == 0
}
/// Make this blob immutable.
pub fn make_immutable(&mut self) {
unsafe { sys::hb_blob_make_immutable(self.raw); }
}
/// Returns true if the blob is immutable.
pub fn is_immutable(&self) -> bool {
unsafe { sys::hb_blob_is_immutable(self.raw) != 0 }
}
/// Borrows a raw pointer to the blob.
pub fn as_raw(&self) -> *mut sys::hb_blob_t {
self.raw
}
/// Gives up ownership and returns a raw pointer to the blob.
pub fn into_raw(self) -> *mut sys::hb_blob_t {
let raw = self.raw;
mem::forget(self);
raw
}
}
impl<'a> ops::Deref for Blob<'a> {
type Target = [u8];
fn deref(&self) -> &[u8] {
unsafe {
let mut len = 0;
let ptr = sys::hb_blob_get_data(self.raw, &mut len);
assert!(!ptr.is_null(), "hb_blob_get_data failed");
slice::from_raw_parts(ptr as *const u8, len as usize)
}
}
}
impl<'a> ops::DerefMut for Blob<'a> {
fn deref_mut(&mut self) -> &mut [u8] {
unsafe {
let mut len = 0;
let ptr = sys::hb_blob_get_data_writable(self.raw, &mut len);
assert!(!ptr.is_null(), "hb_blob_get_data_writable failed");
slice::from_raw_parts_mut(ptr as *mut u8, len as usize)
}
}
}
impl<'a> Drop for Blob<'a> {
/// Decrement the reference count, and destroy the blob if the reference count is zero.
fn drop(&mut self) {
unsafe { sys::hb_blob_destroy(self.raw); }
}
}