cotis_utils/
font_manager.rs1use std::sync::{Arc, RwLock, RwLockReadGuard};
6
7pub struct FontManager<Font> {
9 font_data: Arc<RwLock<Box<dyn FontsHolder<Font>>>>,
10}
11
12pub type FontsGuard<'a, Font> = RwLockReadGuard<'a, Box<dyn FontsHolder<Font>>>;
14
15impl<Font> FontManager<Font> {
16 pub fn new<Holder: FontsHolder<Font> + 'static>(font_data: Holder) -> Self {
18 Self {
19 font_data: Arc::new(RwLock::new(Box::new(font_data))),
20 }
21 }
22
23 pub fn leak(self) -> &'static Self {
28 Box::leak(Box::new(self))
29 }
30 pub fn get_fonts(&self) -> FontsGuard<'_, Font> {
36 self.font_data.read().unwrap()
37 }
38 pub fn push_font(&self, font: Font) -> usize {
44 self.font_data.write().unwrap().push_font(font)
45 }
46 pub fn delete_font(&self, index: usize) {
52 self.font_data.write().unwrap().delete_font(index);
53 }
54}
55
56pub trait FontsHolder<Font> {
58 fn get_fonts(&self) -> &[Font];
60 fn push_font(&mut self, font: Font) -> usize;
62 fn delete_font(&mut self, index: usize);
64}
65
66pub struct GenericFontsHolder<Font> {
68 fonts: Vec<Font>,
69 free_fonts: Vec<usize>,
70}
71
72impl<Font> Default for GenericFontsHolder<Font> {
73 fn default() -> Self {
74 Self::new()
75 }
76}
77
78impl<Font> GenericFontsHolder<Font> {
79 pub fn new() -> Self {
81 Self {
82 fonts: vec![],
83 free_fonts: vec![],
84 }
85 }
86}
87
88impl<Font> FontsHolder<Font> for GenericFontsHolder<Font> {
89 fn get_fonts(&self) -> &[Font] {
90 self.fonts.as_slice()
91 }
92
93 fn push_font(&mut self, font: Font) -> usize {
98 if let Some(index) = self.free_fonts.pop() {
99 self.fonts.insert(index, font);
100 index
101 } else {
102 self.fonts.push(font);
103 self.fonts.len() - 1
104 }
105 }
106
107 fn delete_font(&mut self, index: usize) {
108 self.free_fonts.push(index);
109 }
110}
111
112#[cfg(test)]
113mod tests {
114 use super::*;
115
116 #[test]
117 fn generic_fonts_holder_reuses_deleted_slots() {
118 let mut holder = GenericFontsHolder::new();
119 assert_eq!(holder.push_font("a"), 0);
120 assert_eq!(holder.push_font("b"), 1);
121 holder.delete_font(0);
122 assert_eq!(holder.push_font("c"), 0);
123 assert_eq!(holder.get_fonts()[0], "c");
124 assert_eq!(holder.get_fonts()[1], "a");
125 assert_eq!(holder.get_fonts()[2], "b");
126 }
127
128 #[test]
129 fn font_manager_round_trips_through_rwlock() {
130 let manager = FontManager::new(GenericFontsHolder::new());
131 assert_eq!(manager.push_font("font-a"), 0);
132 assert_eq!(manager.get_fonts().get_fonts()[0], "font-a");
133 manager.delete_font(0);
134 assert_eq!(manager.push_font("font-b"), 0);
135 assert_eq!(manager.get_fonts().get_fonts()[0], "font-b");
136 }
137}