Skip to content

Commit 30398c2

Browse files
authored
Merge pull request pop-os#188 from EHfive/use_self_cell
Use self_cell for creating self-referential struct
2 parents 4a6c388 + 331710a commit 30398c2

File tree

2 files changed

+49
-94
lines changed

2 files changed

+49
-94
lines changed

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ rust-version = "1.65"
1313
fontdb = { version = "0.14.1", default-features = false }
1414
libm = "0.2.7"
1515
log = "0.4.20"
16-
aliasable = "0.1.3"
1716
rustybuzz = { version = "0.10.0", default-features = false, features = ["libm"] }
1817
swash = { version = "0.1.8", optional = true }
1918
syntect = { version = "5.1.0", optional = true }
@@ -24,6 +23,7 @@ unicode-segmentation = "1.10.1"
2423
rangemap = "1.3.0"
2524
hashbrown = { version = "0.14.0", optional = true, default-features = false }
2625
rustc-hash = { version = "1.1.0", default-features = false }
26+
self_cell = "1.0.1"
2727

2828
[dependencies.unicode-bidi]
2929
version = "0.3.13"

src/font/mod.rs

+48-93
Original file line numberDiff line numberDiff line change
@@ -1,116 +1,68 @@
11
// SPDX-License-Identifier: MIT OR Apache-2.0
22
pub(crate) mod fallback;
33

4-
use alloc::boxed::Box;
4+
use core::fmt;
5+
56
use alloc::sync::Arc;
67

8+
use rustybuzz::Face as RustybuzzFace;
9+
use self_cell::self_cell;
10+
711
pub use self::system::*;
812
mod system;
913

10-
pub use font_inner::Font;
11-
12-
/// Encapsulates the self-referencing `Font` struct to ensure all field accesses have to go through
13-
/// safe methods.
14-
mod font_inner {
15-
use super::*;
16-
use aliasable::boxed::AliasableBox;
17-
use core::fmt;
14+
self_cell!(
15+
struct OwnedFace {
16+
owner: Arc<dyn AsRef<[u8]> + Send + Sync>,
1817

19-
/// A font
20-
//
21-
// # Safety invariant
22-
//
23-
// `data` must never have a mutable reference taken, nor be modified during the lifetime of
24-
// this `Font`.
25-
pub struct Font {
26-
#[cfg(feature = "swash")]
27-
swash: (u32, swash::CacheKey),
28-
rustybuzz: rustybuzz::Face<'static>,
29-
// Note: This field must be after rustybuzz to ensure that it is dropped later. Otherwise
30-
// there would be a dangling reference when dropping rustybuzz.
31-
data: aliasable::boxed::AliasableBox<Arc<dyn AsRef<[u8]> + Send + Sync>>,
32-
id: fontdb::ID,
18+
#[covariant]
19+
dependent: RustybuzzFace,
3320
}
21+
);
3422

35-
impl fmt::Debug for Font {
36-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
37-
f.debug_struct("Font")
38-
.field("id", &self.id)
39-
.finish_non_exhaustive()
40-
}
41-
}
23+
/// A font
24+
pub struct Font {
25+
#[cfg(feature = "swash")]
26+
swash: (u32, swash::CacheKey),
27+
rustybuzz: OwnedFace,
28+
data: Arc<dyn AsRef<[u8]> + Send + Sync>,
29+
id: fontdb::ID,
30+
}
4231

43-
pub(super) struct FontTryBuilder<
44-
RustybuzzBuilder: for<'this> FnOnce(
45-
&'this Arc<dyn AsRef<[u8]> + Send + Sync>,
46-
) -> Option<rustybuzz::Face<'this>>,
47-
> {
48-
pub(super) id: fontdb::ID,
49-
pub(super) data: Arc<dyn AsRef<[u8]> + Send + Sync>,
50-
pub(super) rustybuzz_builder: RustybuzzBuilder,
51-
#[cfg(feature = "swash")]
52-
pub(super) swash: (u32, swash::CacheKey),
32+
impl fmt::Debug for Font {
33+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
34+
f.debug_struct("Font")
35+
.field("id", &self.id)
36+
.finish_non_exhaustive()
5337
}
54-
impl<
55-
RustybuzzBuilder: for<'this> FnOnce(
56-
&'this Arc<dyn AsRef<[u8]> + Send + Sync>,
57-
) -> Option<rustybuzz::Face<'this>>,
58-
> FontTryBuilder<RustybuzzBuilder>
59-
{
60-
pub(super) fn try_build(self) -> Option<Font> {
61-
unsafe fn change_lifetime<'old, 'new: 'old, T: 'new>(data: &'old T) -> &'new T {
62-
&*(data as *const _)
63-
}
64-
65-
let data: AliasableBox<Arc<dyn AsRef<[u8]> + Send + Sync>> =
66-
AliasableBox::from_unique(Box::new(self.data));
67-
68-
// Safety: We use AliasableBox to allow the references in rustybuzz::Face to alias with
69-
// the data stored behind the AliasableBox. In addition the entire public interface of
70-
// Font ensures that no mutable reference is given to data. And finally we use
71-
// for<'this> for the rustybuzz_builder to ensure it can't leak a reference. Combined
72-
// this ensures that it is sound to produce a self-referential type.
73-
let rustybuzz = (self.rustybuzz_builder)(unsafe { change_lifetime(&*data) })?;
38+
}
7439

75-
Some(Font {
76-
id: self.id,
77-
data,
78-
rustybuzz,
79-
#[cfg(feature = "swash")]
80-
swash: self.swash,
81-
})
82-
}
40+
impl Font {
41+
pub fn id(&self) -> fontdb::ID {
42+
self.id
8343
}
8444

85-
impl Font {
86-
pub fn id(&self) -> fontdb::ID {
87-
self.id
88-
}
89-
90-
pub fn data(&self) -> &[u8] {
91-
// Safety: This only gives an immutable access to `data`.
92-
(**self.data).as_ref()
93-
}
45+
pub fn data(&self) -> &[u8] {
46+
(*self.data).as_ref()
47+
}
9448

95-
pub fn rustybuzz(&self) -> &rustybuzz::Face<'_> {
96-
&self.rustybuzz
97-
}
49+
pub fn rustybuzz(&self) -> &RustybuzzFace<'_> {
50+
self.rustybuzz.borrow_dependent()
51+
}
9852

99-
#[cfg(feature = "swash")]
100-
pub fn as_swash(&self) -> swash::FontRef<'_> {
101-
let swash = &self.swash;
102-
swash::FontRef {
103-
data: self.data(),
104-
offset: swash.0,
105-
key: swash.1,
106-
}
53+
#[cfg(feature = "swash")]
54+
pub fn as_swash(&self) -> swash::FontRef<'_> {
55+
let swash = &self.swash;
56+
swash::FontRef {
57+
data: self.data(),
58+
offset: swash.0,
59+
key: swash.1,
10760
}
10861
}
10962
}
11063

11164
impl Font {
11265
pub fn new(info: &fontdb::FaceInfo) -> Option<Self> {
113-
#[allow(unused_variables)]
11466
let data = match &info.source {
11567
fontdb::Source::Binary(data) => Arc::clone(data),
11668
#[cfg(feature = "std")]
@@ -121,16 +73,19 @@ impl Font {
12173
#[cfg(feature = "std")]
12274
fontdb::Source::SharedFile(_path, data) => Arc::clone(data),
12375
};
124-
font_inner::FontTryBuilder {
76+
77+
Some(Self {
12578
id: info.id,
12679
#[cfg(feature = "swash")]
12780
swash: {
12881
let swash = swash::FontRef::from_index((*data).as_ref(), info.index as usize)?;
12982
(swash.offset, swash.key)
13083
},
84+
rustybuzz: OwnedFace::try_new(Arc::clone(&data), |data| {
85+
RustybuzzFace::from_slice((**data).as_ref(), info.index).ok_or(())
86+
})
87+
.ok()?,
13188
data,
132-
rustybuzz_builder: |data| rustybuzz::Face::from_slice((**data).as_ref(), info.index),
133-
}
134-
.try_build()
89+
})
13590
}
13691
}

0 commit comments

Comments
 (0)