Skip to content

Commit 87fd8c6

Browse files
committed
Add docs and safety comments
1 parent 3815d53 commit 87fd8c6

12 files changed

Lines changed: 205 additions & 34 deletions

File tree

crates/mac_core/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
lints.workspace = true
2+
13
[package]
24
name = "tectonic_mac_core"
35
license = "MIT"

crates/mac_core/build.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
//! Mac core library build script. Links to framework libraries when targeting MacOS.
2+
13
use tectonic_cfg_support::target_cfg;
24

35
fn main() {

crates/mac_core/src/array.rs

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,14 @@ use std::ptr;
55
use std::ptr::NonNull;
66

77
cfty! {
8+
/// A homogeneous array of CFType values, similar to [`Vec`].
89
CFArray<T> : CFArrayGetTypeID
910
}
1011

1112
impl<T: CoreType> CFArray<T> {
13+
/// Create a new, empty [`CFArray`].
1214
pub fn empty() -> CFArray<T> {
15+
// SAFETY: Valid to call with all null and zero length + default callbacks
1316
let ptr = unsafe {
1417
sys::CFArrayCreate(
1518
ptr::null_mut(),
@@ -18,10 +21,15 @@ impl<T: CoreType> CFArray<T> {
1821
&sys::kCFTypeArrayCallBacks,
1922
)
2023
};
21-
CFArray::new_owned(NonNull::new(ptr.cast_mut()).unwrap())
24+
let ptr = NonNull::new(ptr.cast_mut()).unwrap();
25+
// SAFETY: If non-null, pointer from CFArrayCreate is a new, owned CFArray.
26+
unsafe { CFArray::new_owned(ptr) }
2227
}
2328

29+
/// Create a new [`CFArray`] that contains the provided values.
2430
pub fn new(values: &[T]) -> CFArray<T> {
31+
// SAFETY: Length matches provided slice and values are `CoreType` so must be valid
32+
// CFTypeRefs.
2533
let ptr = unsafe {
2634
sys::CFArrayCreate(
2735
ptr::null_mut(),
@@ -30,13 +38,18 @@ impl<T: CoreType> CFArray<T> {
3038
&sys::kCFTypeArrayCallBacks,
3139
)
3240
};
33-
CFArray::new_owned(NonNull::new(ptr.cast_mut()).unwrap())
41+
let ptr = NonNull::new(ptr.cast_mut()).unwrap();
42+
// SAFETY: If non-null, pointer from CFCArrayCreate is a new, owned CFArray.
43+
unsafe { CFArray::new_owned(ptr) }
3444
}
3545

46+
/// Get the length of this array
3647
pub fn len(&self) -> usize {
48+
// SAFETY: Internal pointer is guaranteed valid.
3749
unsafe { sys::CFArrayGetCount(self.0.as_ptr()) as usize }
3850
}
3951

52+
/// Check whether this array is empty
4053
pub fn is_empty(&self) -> bool {
4154
self.len() == 0
4255
}
@@ -46,12 +59,14 @@ impl<T: CoreType> Index<usize> for CFArray<T> {
4659
type Output = T;
4760

4861
fn index(&self, index: usize) -> &Self::Output {
62+
if index >= self.len() {
63+
panic!("Index {index} out of bounds for CFArray");
64+
}
65+
// SAFETY: Internal pointer is guaranteed valid. Index has been verified in-bounds.
4966
let ptr =
5067
unsafe { sys::CFArrayGetValueAtIndex(self.0.cast().as_ptr(), index as sys::CFIndex) }
5168
.cast::<T>();
52-
if ptr.is_null() {
53-
panic!("Index {index} out of bounds for CFArray");
54-
}
69+
// SAFETY: API contracts ensure all values are of the correct type and live for our lifetime.
5570
unsafe { &*ptr }
5671
}
5772
}

crates/mac_core/src/dict.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,14 +42,15 @@ impl<K, V, const N: usize> Pairs for [(K, V); N] {
4242
type Values = [V; N];
4343

4444
fn into_pairs(self) -> (Self::Keys, Self::Values) {
45-
let mut keys: [MaybeUninit<K>; N] = unsafe { MaybeUninit::uninit().assume_init() };
46-
let mut values: [MaybeUninit<V>; N] = unsafe { MaybeUninit::uninit().assume_init() };
45+
let mut keys: [MaybeUninit<K>; N] = [const { MaybeUninit::uninit() }; N];
46+
let mut values: [MaybeUninit<V>; N] = [const { MaybeUninit::uninit() }; N];
4747

4848
for (idx, (key, val)) in self.into_iter().enumerate() {
4949
keys[idx].write(key);
5050
values[idx].write(val);
5151
}
5252

53+
// SAFETY: All values in both arrays have been initialized
5354
unsafe {
5455
(
5556
mem::transmute_copy::<_, [K; N]>(&keys),
@@ -69,13 +70,17 @@ impl<K, V> Pairs for Vec<(K, V)> {
6970
}
7071

7172
cfty! {
73+
/// A dictionary / map of CFType keys to values, similar to [`HashMap`](std::collections::HashMap)
7274
CFDictionary<K, V> : CFDictionaryGetTypeID
7375
}
7476

7577
impl<K: CoreType, V: CoreType> CFDictionary<K, V> {
78+
/// Create a new [`CFDictionary`] that contains the provided key/value pairs.
7679
pub fn new<P: Pairs>(pairs: P) -> CFDictionary<K, V> {
7780
let (keys, values) = pairs.into_pairs();
7881

82+
// SAFETY: Length matches provided slices and values are `CoreType` so must be valid
83+
// CFTypeRefs.
7984
let ptr = unsafe {
8085
sys::CFDictionaryCreate(
8186
ptr::null_mut(),
@@ -86,6 +91,8 @@ impl<K: CoreType, V: CoreType> CFDictionary<K, V> {
8691
&sys::kCFTypeDictionaryValueCallBacks,
8792
)
8893
};
89-
CFDictionary::new_owned(NonNull::new(ptr.cast_mut()).unwrap())
94+
let ptr = NonNull::new(ptr.cast_mut()).unwrap();
95+
// SAFETY: If non-null, pointer from CFDictionaryCreate is a new, owned CFDictionary.
96+
unsafe { CFDictionary::new_owned(ptr) }
9097
}
9198
}

crates/mac_core/src/font.rs

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,84 +2,127 @@ use super::{sys, CFString, CFType, CTFontDescriptor, CoreType};
22
use std::ptr;
33
use std::ptr::NonNull;
44

5+
/// An attribute that may be found in a font, such as family name or URL.
56
#[derive(Copy, Clone)]
67
pub enum FontAttribute {
8+
/// Name
79
Name,
10+
/// Family Name
811
FamilyName,
12+
/// Display Name
913
DisplayName,
14+
/// URL
1015
URL,
16+
/// Cascade List - fallbacks to use if glyph not present in this font.
1117
CascadeList,
1218
}
1319

1420
impl FontAttribute {
21+
/// Convert this attribute into its matching [`CFString`].
1522
pub fn to_str(self) -> CFString {
16-
CFString::new_borrowed(NonNull::new(self.to_raw().cast_mut()).unwrap())
23+
let ptr = NonNull::new(self.to_raw().cast_mut()).unwrap();
24+
// SAFETY: The value returned by `to_raw` is guaranteed to be a valid CFStringRef
25+
unsafe { CFString::new_borrowed(ptr) }
1726
}
1827

28+
/// Convert this attribute into a raw pointer to a [`CFString`].
1929
pub fn to_raw(self) -> sys::CFStringRef {
2030
match self {
31+
// SAFETY: Static guaranteed to exist and by a valid CFStringRef
2132
FontAttribute::Name => unsafe { sys::kCTFontNameAttribute },
33+
// SAFETY: sic
2234
FontAttribute::FamilyName => unsafe { sys::kCTFontFamilyNameAttribute },
35+
// SAFETY: sic
2336
FontAttribute::DisplayName => unsafe { sys::kCTFontDisplayNameAttribute },
37+
// SAFETY: sic
2438
FontAttribute::URL => unsafe { sys::kCTFontURLAttribute },
39+
// SAFETY: sic
2540
FontAttribute::CascadeList => unsafe { sys::kCTFontCascadeListAttribute },
2641
}
2742
}
2843
}
2944

45+
/// A type of font name that may be available.
3046
#[derive(Copy, Clone)]
3147
pub enum FontNameKey {
48+
/// Full name
3249
Full,
50+
/// Family name
3351
Family,
52+
/// Style name
3453
Style,
54+
/// PostScript name
3555
PostScript,
3656
}
3757

3858
impl FontNameKey {
59+
/// Convert this attribute into its matching [`CFString`].
3960
pub fn to_str(self) -> CFString {
40-
CFString::new_borrowed(NonNull::new(self.to_raw().cast_mut()).unwrap())
61+
let ptr = NonNull::new(self.to_raw().cast_mut()).unwrap();
62+
// SAFETY: The value returned by `to_raw` is guaranteed to be a valid CFStringRef
63+
unsafe { CFString::new_borrowed(ptr) }
4164
}
4265

4366
fn to_raw(self) -> sys::CFStringRef {
4467
match self {
68+
// SAFETY: Static guaranteed to exist and by a valid CFStringRef
4569
FontNameKey::Full => unsafe { sys::kCTFontFullNameKey },
70+
// SAFETY: sic
4671
FontNameKey::Family => unsafe { sys::kCTFontFamilyNameKey },
72+
// SAFETY: sic
4773
FontNameKey::Style => unsafe { sys::kCTFontStyleNameKey },
74+
// SAFETY: sic
4875
FontNameKey::PostScript => unsafe { sys::kCTFontPostScriptNameKey },
4976
}
5077
}
5178
}
5279

5380
cfty! {
81+
/// A font, combining a descriptor and a size, as well as any other necessary transforms to
82+
/// render glyphs.
5483
CTFont : CTFontGetTypeID
5584
}
5685

5786
impl CTFont {
87+
/// Create a new font from a [`CTFontDescriptor`] and a size to render at.
5888
pub fn new_descriptor(descriptor: &CTFontDescriptor, size: f64) -> CTFont {
89+
// SAFETY: Provided descriptor is guaranteed valid. Any size will work. Null matrix is always
90+
// allowed.
5991
let ptr = unsafe {
6092
sys::CTFontCreateWithFontDescriptor(
6193
descriptor.as_type_ref(),
6294
size as sys::CGFloat,
6395
ptr::null_mut(),
6496
)
6597
};
66-
CTFont::new_owned(NonNull::new(ptr.cast_mut()).unwrap())
98+
let ptr = NonNull::new(ptr.cast_mut()).unwrap();
99+
// SAFETY: If non-null, pointer from CTFontCreateWithFontDescriptor is a new, owned CTFont.
100+
unsafe { CTFont::new_owned(ptr) }
67101
}
68102

103+
/// Get an attribute of this font, if present
69104
pub fn attr(&self, attr: FontAttribute) -> Option<CFType> {
105+
// SAFETY: Internal pointer and attribute string guaranteed valid.
70106
let ptr = unsafe { sys::CTFontCopyAttribute(self.as_type_ref(), attr.to_raw()) };
71-
NonNull::new(ptr.cast_mut()).map(CFType::new_owned)
107+
// SAFETY: In non-null, returned name guaranteed valid and owned.
108+
NonNull::new(ptr.cast_mut()).map(|ptr| unsafe { CFType::new_owned(ptr) })
72109
}
73110

111+
/// Get a name value of this font, if present
74112
pub fn name(&self, name: FontNameKey) -> Option<CFString> {
113+
// SAFETY: Internal pointer and name string guaranteed valid.
75114
let ptr = unsafe { sys::CTFontCopyName(self.as_type_ref(), name.to_raw()) };
76-
NonNull::new(ptr.cast_mut()).map(CFString::new_owned)
115+
// SAFETY: In non-null, returned name guaranteed valid and owned.
116+
NonNull::new(ptr.cast_mut()).map(|ptr| unsafe { CFString::new_owned(ptr) })
77117
}
78118

119+
/// Get the name of this font, localized to a specific language
79120
pub fn localized_name(&self, name: FontNameKey) -> Option<CFString> {
121+
// SAFETY: Internal pointer and name string guaranteed valid.
80122
let ptr = unsafe {
81123
sys::CTFontCopyLocalizedName(self.as_type_ref(), name.to_raw(), ptr::null_mut())
82124
};
83-
NonNull::new(ptr.cast_mut()).map(CFString::new_owned)
125+
// SAFETY: In non-null, returned name guaranteed valid and owned.
126+
NonNull::new(ptr.cast_mut()).map(|ptr| unsafe { CFString::new_owned(ptr) })
84127
}
85128
}

crates/mac_core/src/font_desc.rs

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,39 +2,58 @@ use super::{sys, CFArray, CFDictionary, CFSet, CFString, CFType, CoreType, FontA
22
use std::ptr::NonNull;
33

44
cfty! {
5+
/// A font descriptor, a typeface that can be paired with a size and transform to get a specific
6+
/// font.
57
CTFontDescriptor : CTFontDescriptorGetTypeID
68
}
79

810
impl CTFontDescriptor {
11+
/// Create a new descriptor from a dictionary of its attributes. Unrecognized attributes will
12+
/// be ignored.
913
pub fn new_with_attrs(attrs: &CFDictionary<CFString, CFType>) -> CTFontDescriptor {
14+
// SAFETY: Attrs is guaranteed to be valid
1015
let ptr = unsafe { sys::CTFontDescriptorCreateWithAttributes(attrs.as_type_ref()) };
11-
CTFontDescriptor::new_owned(NonNull::new(ptr.cast_mut()).unwrap())
16+
let ptr = NonNull::new(ptr.cast_mut()).unwrap();
17+
// SAFETY: If non-null, pointer from CTFontDescriptorCreateWithAttributes is a new, owned CTFontDescriptor.
18+
unsafe { CTFontDescriptor::new_owned(ptr) }
1219
}
1320

21+
/// Create a copy of this descriptor, but with additional attributes as specified by `attrs`.
22+
/// Overlapping attributes are replaced.
1423
pub fn copy_with_attrs(&self, attrs: &CFDictionary<CFString, CFType>) -> CTFontDescriptor {
24+
// SAFETY: Self and attrs are guaranteed to be valid
1525
let ptr = unsafe {
1626
sys::CTFontDescriptorCreateCopyWithAttributes(self.as_type_ref(), attrs.as_type_ref())
1727
};
18-
CTFontDescriptor::new_owned(NonNull::new(ptr.cast_mut()).unwrap())
28+
let ptr = NonNull::new(ptr.cast_mut()).unwrap();
29+
// SAFETY: If non-null, pointer from CTFontDescriptorCreateCopyWithAttributes is a new, owned CTFontDescriptor.
30+
unsafe { CTFontDescriptor::new_owned(ptr) }
1931
}
2032

33+
/// Find all loaded fonts that contain the provided mandatory properties.
2134
pub fn matching_font_descriptors(
2235
&self,
2336
mandatory: &CFSet<CFString>,
2437
) -> CFArray<CTFontDescriptor> {
38+
// SAFETY: Self and mandatory are guaranteed to be valid
2539
let ptr = unsafe {
2640
sys::CTFontDescriptorCreateMatchingFontDescriptors(
2741
self.as_type_ref(),
2842
mandatory.as_type_ref(),
2943
)
3044
};
3145
NonNull::new(ptr.cast_mut())
32-
.map(CFArray::new_owned)
46+
// SAFETY: If non-null, pointer from CTFontDescriptorCreateMatchingFontDescriptors is a
47+
// new, owned CFArray of CTFontDescriptor
48+
.map(|ptr| unsafe { CFArray::new_owned(ptr) })
3349
.unwrap_or_else(CFArray::empty)
3450
}
3551

52+
/// Get an attribute of this font descriptor, if present.
3653
pub fn attr(&self, attr: FontAttribute) -> Option<CFType> {
54+
// SAFETY: Self and attr are guaranteed to be valid
3755
let ptr = unsafe { sys::CTFontDescriptorCopyAttribute(self.as_type_ref(), attr.to_raw()) };
38-
NonNull::new(ptr.cast_mut()).map(CFType::new_owned)
56+
// SAFETY: If non-null, pointer from CTFontDescriptorCreateMatchingFontDescriptors is a new, owned CFType instance
57+
NonNull::new(ptr.cast_mut()).map(|ptr| unsafe { CFType::new_owned(ptr) })
3958
}
4059
}

0 commit comments

Comments
 (0)