// 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 or the MIT license // , 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>`. /// /// 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>) -> 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)); } 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); } } }