// 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 crate::sys;
use core::ffi::{c_char, c_uint};
use core::marker::PhantomData;
use core::{mem, ops, ptr, slice};
#[cfg(feature =
"std")]
use std::{ffi::c_void, sync::Arc, vec::Vec};
/// 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
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.
///
/// ✨ *Enabled with the `std` Cargo feature.*
///
/// ```
/// # 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());
/// ```
#[cfg(feature =
"std")]
pub fn new_from_arc_vec(data: Arc<Vec<u8>>) -> Blob<
'static> {
let len = data.len();
assert!(len <= c_uint::MAX
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.
///
/// # Safety
///
/// The pointer must be valid and must not be used after this function is called.
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 ops::Deref for Blob<
'_> {
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 ops::DerefMut for Blob<
'_> {
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 Drop for Blob<
'_> {
/// 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);
}
}
}