我正在使用rustybuzz和wasm-bindgen在HTML5画布上排版文本。我想创建一个全局字体缓存,由String
s索引,这样我就可以加载和解析字体文件一次,然后多次重用它们(提示关于全局变量是如何坏的评论……如果有人有更好的方法,请告诉我)。具体来说,我想要一个可以在任何地方访问的HashMap<String, rustybuzz::Face>
的变体。然后,我想将register_font
函数暴露给JavaScript端,以便我可以加载ArrayBuffers
,例如:
#[wasm_bindgen]
pub fn register_font(name: &str, font_data: &[u8]) {
MY_FONT_CACHE_SOMEHOW.insert(
name.to_string(),
rustybuzz::Face::from_slice(&font_data, 0).unwrap()
);
}
并且,为了完成,我希望一个内部get_font
函数来检索:
fn get_font(name: &String) -> rustybuzz::Face {
MY_FONT_CACHE_SOMEHOW.get(name).unwrap()
}
我知道我有可变生命周期的问题,我只是不知道如何解决它们。rustybuzz::Face
结构体只是引用它的内部数据,它并不拥有它。wasm-bindgen
不支持将register_font
函数上的传入ArrayBuffer
/[u8]
标记为'static
,这似乎是主要问题之一。但我对铁锈这事还是新手。有人知道怎么做这个(或更好的方法)吗?
如果您只添加哈希表而从不删除,则可以复制和泄漏font_data以使其静态:
#[wasm_bindgen]
pub fn register_font(name: &str, font_data: &[u8]) {
let font_data: &'static [u8] = font_data.to_owned().leak();
//...
}
如果你想能够从缓存中删除字体,你必须保持font_data
和Face
在一起。这就是臭名昭著的self-referential type
问题。
你可以采取不安全的方式,保持一个指针指向一个动态分配的*const [u8]
类型,或者你可以使用一个尝试解决这个问题的板条箱。
目前我最喜欢的是ouroboros
:它应该是这样的(未经测试):
#[self_referencing]
struct MyFace {
font_data: Vec<u8>,
#[borrows(font_data)]
face: Face<'this>,
}
#[wasm_bindgen]
pub fn register_font(name: &str, font_data: &[u8]) {
let face = MyFaceBuilder {
font_data: font_data.to_owned(),
face_builder: |font_data: &[u8]| Face::from_slice(font_data).unwrap(),
}.build();
MY_FONT_CACHE_SOMEHOW.insert(
name.to_string(),
face,
);
}