harfbuzz 0.3.1

Rust bindings to the HarfBuzz text shaping engine
Documentation
// 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); }
    }
}