Skip to content

Commit

Permalink
chore!: Move map and set to modules
Browse files Browse the repository at this point in the history
  • Loading branch information
henkkuli committed Nov 19, 2023
1 parent 1e2c2d4 commit 041720c
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 44 deletions.
4 changes: 3 additions & 1 deletion src/font_face.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use std::{ffi::c_char, marker::PhantomData, ops::Deref, ptr::null_mut};

use crate::{sys, AllocationError, Blob, CharSet, FontFaceExtractionError, Language, Map};
use crate::{
map::Map, set::CharSet, sys, AllocationError, Blob, FontFaceExtractionError, Language,
};

/// A font face is an object that represents a single face from within a font family.
///
Expand Down
12 changes: 5 additions & 7 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@
//! In other words, subsetting allows you to take a large font and construct a new, smaller font which has only those
//! characters that you need. Be sure to check the license of the font though, as not all fonts can be legally
//! subsetted.
//!
//!
//! # Why?
//! Many modern fonts can contain hundreds or even thousands of glyphs, of which only a couple dozen or maybe hundred is
//! needed in any single document. This also means that modern fonts can be very bulky compared to what is actually
//! needed. The solution to this is font subsetting: We can construct a font that includes only those glyphs and
//! features that are needed for the document.
//!
//!
//! # Usage
//! The simplest way to construct a subset of a font is to use [`subset()`] function. In the following example, we keep
//! only glyphs that are needed show any combination of characters 'a', 'b' and 'c', e.g. "abc" and "cabba" can be
Expand Down Expand Up @@ -59,7 +59,7 @@
//! # Ok(())
//! # }
//! ```
//!
//!
//! # Using bundled version of HarfBuzz
//! By default, this crate uses the system HarfBuzz installation. If it is not available, or it is too old, this crate
//! can also used a bundled copy of HarfBuzz by using feature `bundled`:
Expand All @@ -73,8 +73,8 @@ mod blob;
mod common;
mod error;
mod font_face;
mod map;
mod set;
pub mod map;
pub mod set;
mod subset;

pub mod sys;
Expand All @@ -83,8 +83,6 @@ pub use blob::*;
pub use common::*;
pub use error::*;
pub use font_face::*;
pub use map::*;
pub use set::*;
pub use subset::*;

/// A convenient method to create a subset of a font over given characters.
Expand Down
34 changes: 19 additions & 15 deletions src/map.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
//! Map represents an integer-to-integer mapping.
//!
//! While map in this module can be used as a general-purpose map in Rust code, it is recommended that you instead use
//! [`std::collections::BTreeMap`] or [`std::collections::HashMap`] as those are implemented directly in Rust and do not
//! rely on FFI to work.

use std::{
fmt,
hash::Hash,
iter::{FilterMap, FusedIterator},
marker::PhantomData,
};

use crate::{sys, AllocationError, Set};
use crate::{set::Set, sys, AllocationError};

/// Map objects are integer-to-integer hash-maps.
///
Expand Down Expand Up @@ -124,10 +130,9 @@ where
{
/// Gets an iterator over key-value pairs stored in the map.
#[doc(alias = "hb_map_next")]
pub fn iter(&self) -> MapIter<'_, 'a, K, V> {
MapIter(
MapIterImpl::new(self)
.filter_map(|(k, v)| Some((k.try_into().ok()?, v.try_into().ok()?))),
pub fn iter(&self) -> Iter<'_, 'a, K, V> {
Iter(
IterImpl::new(self).filter_map(|(k, v)| Some((k.try_into().ok()?, v.try_into().ok()?))),
)
}
}
Expand Down Expand Up @@ -217,7 +222,7 @@ where
V: TryFrom<u32>,
{
type Item = (K, V);
type IntoIter = MapIter<'m, 'a, K, V>;
type IntoIter = Iter<'m, 'a, K, V>;

fn into_iter(self) -> Self::IntoIter {
self.iter()
Expand All @@ -226,12 +231,11 @@ where

/// Iterator over [`Map`] key-value pairs.
///
/// Use [`Map::iter`] to construct [`MapIter`].
pub struct MapIter<'m, 'a, K, V>(MapIterFilter<'m, 'a, K, V>);
type MapIterFilter<'m, 'a, K, V> =
FilterMap<MapIterImpl<'m, 'a, K, V>, fn((u32, u32)) -> Option<(K, V)>>;
/// Use [`Map::iter`] to construct [`Iter`].
pub struct Iter<'m, 'a, K, V>(IterFilter<'m, 'a, K, V>);
type IterFilter<'m, 'a, K, V> = FilterMap<IterImpl<'m, 'a, K, V>, fn((u32, u32)) -> Option<(K, V)>>;

impl<'m, 'a, K, V> Iterator for MapIter<'m, 'a, K, V>
impl<'m, 'a, K, V> Iterator for Iter<'m, 'a, K, V>
where
K: TryFrom<u32>,
V: TryFrom<u32>,
Expand All @@ -243,23 +247,23 @@ where
}
}

impl<'m, 'a, K, V> FusedIterator for MapIter<'m, 'a, K, V>
impl<'m, 'a, K, V> FusedIterator for Iter<'m, 'a, K, V>
where
K: TryFrom<u32>,
V: TryFrom<u32>,
{
}

/// Iterator over raw elements over map, disregarding whether they can be represented as (K, V).
struct MapIterImpl<'m, 'a, K, V>(&'m Map<'a, K, V>, i32);
struct IterImpl<'m, 'a, K, V>(&'m Map<'a, K, V>, i32);

impl<'m, 'a, K, V> MapIterImpl<'m, 'a, K, V> {
impl<'m, 'a, K, V> IterImpl<'m, 'a, K, V> {
fn new(map: &'m Map<'a, K, V>) -> Self {
Self(map, -1)
}
}

impl<'m, 'a, K, V> Iterator for MapIterImpl<'m, 'a, K, V> {
impl<'m, 'a, K, V> Iterator for IterImpl<'m, 'a, K, V> {
type Item = (u32, u32);

fn next(&mut self) -> Option<Self::Item> {
Expand Down
47 changes: 27 additions & 20 deletions src/set.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
//! Set represents a mathematical set of integer values.
//!
//! While set in this module can be used as a general-purpose set in Rust code, it is recommended that you instead use
//! [`std::collections::BTreeSet`] or [`std::collections::HashSet`] as those are implemented directly in Rust and do not
//! rely on FFI to work.
//!
//! Sets are used in HarfBuzz in some non-shaping APIs to query certain sets of characters or glyphs, or other integer
//! values.

use std::{
any::TypeId,
fmt,
Expand All @@ -10,8 +19,6 @@ use std::{
use crate::{sys, AllocationError, Tag};

/// Set objects represent a mathematical set of integer values.
///
/// Sets are used in non-shaping APIs to query certain sets of characters or glyphs, or other integer values.
pub struct Set<'a, T>(InnerSet, PhantomData<(&'a (), T)>);

impl<T> Set<'static, T> {
Expand Down Expand Up @@ -39,7 +46,7 @@ impl<'a, T> Set<'a, T> {
/// elements that can be represented as `T`. This is especially evident when the set is over [`char`]s and invalid
/// code points have been added with [`Self::insert_range`].
/// ```
/// # use hb_subset::CharSet;
/// # use hb_subset::set::CharSet;
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let mut set = CharSet::new()?;
/// set.insert_range('\u{D7FF}'..'\u{E000}'); // Add all surrogate pairs (and \u{D7FF} for technical reasons)
Expand Down Expand Up @@ -164,15 +171,15 @@ where
///
/// Will panic if `range` explicitly contains [`sys::HB_SET_VALUE_INVALID`]:
/// ```should_panic
/// # use hb_subset::U32Set;
/// # use hb_subset::set::U32Set;
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// U32Set::new()?.insert_range(u32::MAX-10..=u32::MAX);
/// # Ok(())
/// # }
/// ```
/// These still work:
/// ```
/// # use hb_subset::U32Set;
/// # use hb_subset::set::U32Set;
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// U32Set::new()?.insert_range(u32::MAX-10..);
/// U32Set::new()?.insert_range(u32::MAX-10..u32::MAX);
Expand Down Expand Up @@ -213,8 +220,8 @@ where
/// Constructs an iterator over the set.
#[doc(alias = "hb_set_next")]
#[doc(alias = "hb_set_previous")]
pub fn iter(&self) -> SetIter<'_, 'a, T> {
SetIter(SetIterImpl::new(self).filter_map(|v| v.try_into().ok()))
pub fn iter(&self) -> Iter<'_, 'a, T> {
Iter(IterImpl::new(self).filter_map(|v| v.try_into().ok()))
}
}

Expand Down Expand Up @@ -295,7 +302,7 @@ where
T: TryFrom<u32>,
{
type Item = T;
type IntoIter = SetIter<'s, 'a, T>;
type IntoIter = Iter<'s, 'a, T>;

fn into_iter(self) -> Self::IntoIter {
self.iter()
Expand All @@ -304,11 +311,11 @@ where

/// Iterator over [`Set`].
///
/// Use [`Set::iter`] to construct a [`SetIter`].
pub struct SetIter<'s, 'a, T>(SetIterFilter<'s, 'a, T>);
type SetIterFilter<'s, 'a, T> = FilterMap<SetIterImpl<'s, 'a, T>, fn(u32) -> Option<T>>;
/// Use [`Set::iter`] to construct a [`Iter`].
pub struct Iter<'s, 'a, T>(IterFilter<'s, 'a, T>);
type IterFilter<'s, 'a, T> = FilterMap<IterImpl<'s, 'a, T>, fn(u32) -> Option<T>>;

impl<'s, 'a, T> Iterator for SetIter<'s, 'a, T>
impl<'s, 'a, T> Iterator for Iter<'s, 'a, T>
where
T: TryFrom<u32>,
{
Expand All @@ -319,7 +326,7 @@ where
}
}

impl<'s, 'a, T> DoubleEndedIterator for SetIter<'s, 'a, T>
impl<'s, 'a, T> DoubleEndedIterator for Iter<'s, 'a, T>
where
T: TryFrom<u32>,
{
Expand All @@ -328,15 +335,15 @@ where
}
}

impl<'s, 'a, T> FusedIterator for SetIter<'s, 'a, T> where T: TryFrom<u32> {}
impl<'s, 'a, T> FusedIterator for Iter<'s, 'a, T> where T: TryFrom<u32> {}

/// Actual implementation for [`SetIter`].
/// Actual implementation for [`Iter`].
///
/// This implementation does not care whether the target type can or cannot represent the target type. It just returns
/// [`u32`], no matter what. [`SetIter`] is responsible to then filter out invalid values.
struct SetIterImpl<'s, 'a, T>(&'s Set<'a, T>, u32, u32);
/// [`u32`], no matter what. [`Iter`] is responsible to then filter out invalid values.
struct IterImpl<'s, 'a, T>(&'s Set<'a, T>, u32, u32);

impl<'s, 'a, T> SetIterImpl<'s, 'a, T> {
impl<'s, 'a, T> IterImpl<'s, 'a, T> {
const LAST_VALUE: u32 = sys::HB_SET_VALUE_INVALID - 1;
fn new(set: &'s Set<'a, T>) -> Self {
#[allow(clippy::assertions_on_constants, clippy::absurd_extreme_comparisons)]
Expand All @@ -350,7 +357,7 @@ impl<'s, 'a, T> SetIterImpl<'s, 'a, T> {
}
}

impl<'s, 'a, T> Iterator for SetIterImpl<'s, 'a, T> {
impl<'s, 'a, T> Iterator for IterImpl<'s, 'a, T> {
type Item = u32;

fn next(&mut self) -> Option<Self::Item> {
Expand Down Expand Up @@ -378,7 +385,7 @@ impl<'s, 'a, T> Iterator for SetIterImpl<'s, 'a, T> {
}
}

impl<'s, 'a, T> DoubleEndedIterator for SetIterImpl<'s, 'a, T> {
impl<'s, 'a, T> DoubleEndedIterator for IterImpl<'s, 'a, T> {
fn next_back(&mut self) -> Option<Self::Item> {
match self.2 {
0 => {
Expand Down
6 changes: 5 additions & 1 deletion src/subset.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
use std::{marker::PhantomData, ptr::null_mut};

use crate::{sys, AllocationError, CharSet, FontFace, Map, Set, SubsettingError, TagSet, U32Set};
use crate::{
map::Map,
set::{CharSet, Set, TagSet, U32Set},
sys, AllocationError, FontFace, SubsettingError,
};

mod flags;

Expand Down

0 comments on commit 041720c

Please sign in to comment.