reflexo/vector/ir/
module.rs

1use std::{
2    borrow::Borrow,
3    collections::{BTreeMap, HashMap},
4    hash::Hash,
5    ops::Deref,
6    sync::{atomic::AtomicU64, Arc},
7};
8
9use comemo::Prehashed;
10
11use crate::{hash::Fingerprint, ImmutStr, TakeAs};
12
13use super::{preludes::*, *};
14
15pub type ItemMap = BTreeMap<Fingerprint, VecItem>;
16
17pub type RefItemMap = HashMap<Fingerprint, (u64, VecItem)>;
18#[cfg(feature = "item-dashmap")]
19pub type RefItemMapSync = crate::adt::CHashMap<Fingerprint, (AtomicU64, VecItem)>;
20pub type RefItemMapT<V> = crate::adt::FingerprintMap<V>;
21pub type RefItemMapSync = RefItemMapT<(AtomicU64, VecItem)>;
22
23pub trait ToItemMap {
24    fn to_item_map(self) -> ItemMap;
25}
26
27impl ToItemMap for RefItemMap {
28    fn to_item_map(self) -> ItemMap {
29        self.into_iter().map(|(k, (_, v))| (k, v)).collect::<_>()
30    }
31}
32
33impl ToItemMap for RefItemMapSync {
34    fn to_item_map(self) -> ItemMap {
35        self.into_items().map(|(k, (_, v))| (k, v)).collect::<_>()
36    }
37}
38
39/// Trait of a streaming representation of a module.
40pub trait ModuleStream {
41    fn items(&self) -> ItemPack;
42    fn layouts(&self) -> Arc<Vec<LayoutRegion>>;
43    fn fonts(&self) -> Arc<IncrFontPack>;
44    fn glyphs(&self) -> Arc<IncrGlyphPack>;
45    fn gc_items(&self) -> Option<Vec<Fingerprint>> {
46        // never gc items
47        None
48    }
49}
50
51/// A finished module that stores all the vector items.
52/// The vector items shares the underlying data.
53/// The vector items are flattened and ready to be serialized.
54#[derive(Debug, Default, Clone, Hash)]
55pub struct Module {
56    pub fonts: Vec<FontItem>,
57    pub glyphs: Vec<(GlyphRef, FlatGlyphItem)>,
58    pub items: ItemMap,
59}
60
61impl Module {
62    pub fn freeze(self) -> FrozenModule {
63        FrozenModule(Arc::new(Prehashed::new(self)))
64    }
65
66    pub fn prepare_glyphs(&mut self) {
67        let glyphs = std::mem::take(&mut self.glyphs);
68        if glyphs.is_empty() {
69            return;
70        }
71        let mut hash2idx = HashMap::new();
72        for (id, item) in glyphs.into_iter() {
73            let idx = hash2idx.entry(id.font_hash).or_insert_with(|| {
74                self.fonts
75                    .iter()
76                    .position(|f| f.hash == id.font_hash)
77                    .unwrap()
78            });
79            let font = &mut self.fonts[*idx];
80            if font.glyphs.len() <= id.glyph_idx as usize {
81                font.glyphs
82                    .resize(id.glyph_idx as usize + 1, Arc::new(FlatGlyphItem::None));
83            }
84            font.glyphs[id.glyph_idx as usize] = Arc::new(item);
85            if font.glyph_cov.is_empty() {
86                font.glyph_cov = bitvec::vec::BitVec::repeat(false, 65536);
87            }
88            font.glyph_cov.set(id.glyph_idx as usize, true);
89        }
90    }
91
92    /// Get a font item by its stable ref.
93    pub fn get_font(&self, id: &FontRef) -> Option<&FontItem> {
94        self.fonts.get(id.idx as usize)
95    }
96
97    /// Get a svg item by its stable ref.
98    pub fn get_item(&self, id: &Fingerprint) -> Option<&VecItem> {
99        self.items.get(id)
100    }
101
102    pub fn merge_delta(&mut self, v: impl ModuleStream) {
103        let item_pack: ItemPack = v.items();
104        if let Some(gc_items) = v.gc_items() {
105            for id in gc_items {
106                self.items.remove(&id);
107            }
108        }
109        self.items.extend(item_pack.0);
110
111        let fonts = v.fonts();
112        self.fonts.extend(fonts.take().items);
113
114        let glyphs = v.glyphs();
115        if !glyphs.items.is_empty() {
116            self.glyphs = glyphs.take().items;
117            self.prepare_glyphs();
118        }
119    }
120
121    pub fn glyphs_all(&self) -> impl Iterator<Item = (GlyphRef, &FlatGlyphItem)> {
122        self.fonts.iter().flat_map(|font| {
123            font.glyph_cov.iter_ones().map(move |glyph_idx| {
124                (
125                    GlyphRef {
126                        font_hash: font.hash,
127                        glyph_idx: glyph_idx as u32,
128                    },
129                    font.glyphs[glyph_idx].deref(),
130                )
131            })
132        })
133    }
134}
135
136#[derive(Debug, Clone, Hash, PartialEq, Eq)]
137pub struct FrozenModule(pub Arc<Prehashed<Module>>);
138
139pub struct ModuleView {
140    module: Module,
141}
142
143impl ModuleView {
144    /// See [`std::path::Path`]
145    pub fn new<M: AsRef<Module> + ?Sized>(m: &M) -> &Self {
146        // SAFETY: The std::path::Path does similar conversion and is safe.
147        unsafe { &*(m.as_ref() as *const Module as *const ModuleView) }
148    }
149}
150
151impl ToOwned for ModuleView {
152    type Owned = Module;
153
154    fn to_owned(&self) -> Self::Owned {
155        self.module.clone()
156    }
157}
158
159impl AsRef<Module> for ModuleView {
160    #[inline]
161    fn as_ref(&self) -> &Module {
162        &self.module
163    }
164}
165
166impl AsRef<Module> for Module {
167    #[inline]
168    fn as_ref(&self) -> &Module {
169        self
170    }
171}
172
173impl AsRef<Module> for FrozenModule {
174    #[inline]
175    fn as_ref(&self) -> &Module {
176        self.0.deref().deref()
177    }
178}
179
180impl AsRef<FrozenModule> for FrozenModule {
181    #[inline]
182    fn as_ref(&self) -> &FrozenModule {
183        self
184    }
185}
186
187impl Borrow<ModuleView> for FrozenModule {
188    fn borrow(&self) -> &ModuleView {
189        ModuleView::new(self)
190    }
191}
192
193impl Borrow<ModuleView> for Module {
194    fn borrow(&self) -> &ModuleView {
195        ModuleView::new(self)
196    }
197}
198
199impl Borrow<Module> for FrozenModule {
200    fn borrow(&self) -> &Module {
201        self.0.deref().deref()
202    }
203}
204
205/// metadata that can be attached to a module.
206#[derive(Clone)]
207#[cfg_attr(feature = "rkyv", derive(Archive, rDeser, rSer))]
208#[cfg_attr(feature = "rkyv-validation", archive(check_bytes))]
209#[repr(C, align(32))]
210pub enum PageMetadata {
211    GarbageCollection(Vec<Fingerprint>),
212    Item(ItemPack),
213    Glyph(Arc<IncrGlyphPack>),
214    Custom(Vec<(ImmutStr, ImmutBytes)>),
215}
216
217impl fmt::Debug for PageMetadata {
218    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
219        match self {
220            PageMetadata::GarbageCollection(v) => f
221                .debug_struct("GarbageCollection")
222                .field("len", &v.len())
223                .finish(),
224            PageMetadata::Item(v) => f.debug_struct("Item").field("len", &v.0.len()).finish(),
225            PageMetadata::Glyph(v) => f
226                .debug_struct("Glyph")
227                .field("len", &v.items.len())
228                .field("base", &v.incremental_base)
229                .finish(),
230            PageMetadata::Custom(v) => {
231                write!(f, "Custom")?;
232                f.debug_map()
233                    .entries(
234                        v.iter()
235                            .map(|(k, v)| (k.as_ref(), format!("Bytes({})", v.len()))),
236                    )
237                    .finish()
238            }
239        }
240    }
241}
242
243#[derive(Debug, Clone, PartialEq)]
244#[cfg_attr(feature = "rkyv", derive(Archive, rDeser, rSer))]
245#[cfg_attr(feature = "rkyv-validation", archive(check_bytes))]
246pub struct BuildInfo {
247    pub version: ImmutStr,
248    pub compiler: ImmutStr,
249}
250
251/// metadata that can be attached to a module.
252#[derive(Debug, Clone)]
253#[repr(C, align(32))]
254#[cfg_attr(feature = "rkyv", derive(Archive, rDeser, rSer))]
255#[cfg_attr(feature = "rkyv-validation", archive(check_bytes))]
256pub enum ModuleMetadata {
257    BuildVersion(Arc<BuildInfo>),
258    SourceMappingData(Vec<SourceMappingNode>),
259    PageSourceMapping(Arc<LayoutSourceMapping>),
260    GarbageCollection(Vec<Fingerprint>),
261    Item(ItemPack),
262    Font(Arc<IncrFontPack>),
263    Glyph(Arc<IncrGlyphPack>),
264    Layout(Arc<Vec<LayoutRegion>>),
265}
266
267const _: () = assert!(core::mem::size_of::<ModuleMetadata>() == 32);
268
269#[repr(usize)]
270#[allow(dead_code)]
271enum MetaIndices {
272    Version,
273    SourceMapping,
274    PageSourceMapping,
275    GarbageCollection,
276    Item,
277    Font,
278    Glyph,
279    Layout,
280    Max,
281}
282
283const META_INDICES_MAX: usize = MetaIndices::Max as usize;
284
285/// Flatten module so that it can be serialized.
286#[derive(Debug)]
287#[cfg_attr(feature = "rkyv", derive(Archive, rDeser, rSer))]
288#[cfg_attr(feature = "rkyv-validation", archive(check_bytes))]
289pub struct FlatModule {
290    pub magic: [u8; 8],
291    pub metadata: Vec<ModuleMetadata>,
292
293    #[cfg_attr(feature = "rkyv", with(rkyv::with::Skip))]
294    #[allow(unused)]
295    meta_indices: [std::sync::OnceLock<usize>; META_INDICES_MAX],
296}
297
298impl Default for FlatModule {
299    fn default() -> Self {
300        Self {
301            magic: *b"tsvr\x00\x00\x00\x00",
302            metadata: vec![],
303            meta_indices: Default::default(),
304        }
305    }
306}
307
308#[cfg(feature = "rkyv")]
309impl FlatModule {
310    pub fn new(metadata: Vec<ModuleMetadata>) -> Self {
311        Self {
312            metadata,
313            ..Default::default()
314        }
315    }
316
317    pub fn to_bytes(self: &FlatModule) -> Vec<u8> {
318        // Or you can customize your serialization for better performance
319        // and compatibility with #![no_std] environments
320        use rkyv::ser::{serializers::AllocSerializer, Serializer};
321
322        let mut serializer = AllocSerializer::<0>::default();
323        serializer.serialize_value(self).unwrap();
324        let bytes = serializer.into_serializer().into_inner();
325
326        bytes.into_vec()
327    }
328}
329
330// todo: for archived module.
331// todo: zero copy
332#[cfg(feature = "rkyv")]
333impl ModuleStream for &FlatModule {
334    fn items(&self) -> ItemPack {
335        // cache the index
336        let sz = &self.meta_indices[MetaIndices::Item as usize];
337        let sz = sz.get_or_init(|| {
338            let mut sz = usize::MAX; // will panic if not found
339            for (idx, m) in self.metadata.iter().enumerate() {
340                if let ModuleMetadata::Item(_) = m {
341                    sz = idx;
342                    break;
343                }
344            }
345            sz
346        });
347
348        // get the item pack
349        let m = &self.metadata[*sz];
350        if let ModuleMetadata::Item(v) = m {
351            v.clone()
352        } else {
353            unreachable!()
354        }
355    }
356
357    fn layouts(&self) -> Arc<Vec<LayoutRegion>> {
358        // cache the index
359        let sz = &self.meta_indices[MetaIndices::Layout as usize];
360        let sz = sz.get_or_init(|| {
361            let mut sz = usize::MAX; // will panic if not found
362            for (idx, m) in self.metadata.iter().enumerate() {
363                if let ModuleMetadata::Layout(_) = m {
364                    sz = idx;
365                    break;
366                }
367            }
368            sz
369        });
370
371        // get the item pack
372        let m = &self.metadata[*sz];
373        if let ModuleMetadata::Layout(v) = m {
374            v.clone()
375        } else {
376            unreachable!()
377        }
378    }
379
380    fn fonts(&self) -> Arc<IncrFontPack> {
381        // cache the index
382        let sz = &self.meta_indices[MetaIndices::Font as usize];
383        let sz = sz.get_or_init(|| {
384            let mut sz = usize::MAX; // will panic if not found
385            for (idx, m) in self.metadata.iter().enumerate() {
386                if let ModuleMetadata::Font(_) = m {
387                    sz = idx;
388                    break;
389                }
390            }
391            sz
392        });
393
394        // get the item pack
395        let m = &self.metadata[*sz];
396        if let ModuleMetadata::Font(v) = m {
397            v.clone()
398        } else {
399            unreachable!()
400        }
401    }
402
403    fn glyphs(&self) -> Arc<IncrGlyphPack> {
404        // cache the index
405        let sz = &self.meta_indices[MetaIndices::Glyph as usize];
406        let sz = sz.get_or_init(|| {
407            let mut sz = usize::MAX; // will panic if not found
408            for (idx, m) in self.metadata.iter().enumerate() {
409                if let ModuleMetadata::Glyph(_) = m {
410                    sz = idx;
411                    break;
412                }
413            }
414            sz
415        });
416
417        // get the item pack
418        let m = &self.metadata[*sz];
419        if let ModuleMetadata::Glyph(v) = m {
420            v.clone()
421        } else {
422            unreachable!()
423        }
424    }
425
426    fn gc_items(&self) -> Option<Vec<Fingerprint>> {
427        for m in &self.metadata {
428            if let ModuleMetadata::GarbageCollection(v) = m {
429                return Some(v.clone());
430            }
431        }
432        None
433    }
434}