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
308impl FlatModule {
309    pub fn with_capacity(capacity: usize) -> Self {
310        Self {
311            metadata: Vec::with_capacity(capacity),
312            ..Default::default()
313        }
314    }
315
316    /// Adds a metadata to the module.
317    pub fn push(&mut self, m: ModuleMetadata) {
318        self.metadata.push(m);
319    }
320
321    /// Adds single layout
322    pub fn add_single_layout(&mut self, pages: Vec<Page>) {
323        let pages = LayoutRegionNode::new_pages(pages);
324        let pages = Arc::new(vec![LayoutRegion::new_single(pages)]);
325        self.metadata.push(ModuleMetadata::Layout(pages));
326    }
327
328    /// Adds a module.
329    pub fn add_module(&mut self, m: Module) {
330        let Module {
331            glyphs,
332            items,
333            fonts,
334        } = m;
335        self.metadata
336            .push(ModuleMetadata::Font(Arc::new(fonts.into())));
337        self.metadata
338            .push(ModuleMetadata::Glyph(Arc::new(glyphs.into())));
339        self.metadata
340            .push(ModuleMetadata::Item(ItemPack(items.into_iter().collect())));
341    }
342}
343
344#[cfg(feature = "rkyv")]
345impl FlatModule {
346    pub fn new(metadata: Vec<ModuleMetadata>) -> Self {
347        Self {
348            metadata,
349            ..Default::default()
350        }
351    }
352
353    pub fn to_bytes(self: &FlatModule) -> Vec<u8> {
354        // Or you can customize your serialization for better performance
355        // and compatibility with #![no_std] environments
356        use rkyv::ser::{serializers::AllocSerializer, Serializer};
357
358        let mut serializer = AllocSerializer::<0>::default();
359        serializer.serialize_value(self).unwrap();
360        let bytes = serializer.into_serializer().into_inner();
361
362        bytes.into_vec()
363    }
364}
365
366// todo: for archived module.
367// todo: zero copy
368#[cfg(feature = "rkyv")]
369impl ModuleStream for &FlatModule {
370    fn items(&self) -> ItemPack {
371        // cache the index
372        let sz = &self.meta_indices[MetaIndices::Item as usize];
373        let sz = sz.get_or_init(|| {
374            let mut sz = usize::MAX; // will panic if not found
375            for (idx, m) in self.metadata.iter().enumerate() {
376                if let ModuleMetadata::Item(_) = m {
377                    sz = idx;
378                    break;
379                }
380            }
381            sz
382        });
383
384        // get the item pack
385        let m = &self.metadata[*sz];
386        if let ModuleMetadata::Item(v) = m {
387            v.clone()
388        } else {
389            unreachable!()
390        }
391    }
392
393    fn layouts(&self) -> Arc<Vec<LayoutRegion>> {
394        // cache the index
395        let sz = &self.meta_indices[MetaIndices::Layout as usize];
396        let sz = sz.get_or_init(|| {
397            let mut sz = usize::MAX; // will panic if not found
398            for (idx, m) in self.metadata.iter().enumerate() {
399                if let ModuleMetadata::Layout(_) = m {
400                    sz = idx;
401                    break;
402                }
403            }
404            sz
405        });
406
407        // get the item pack
408        let m = &self.metadata[*sz];
409        if let ModuleMetadata::Layout(v) = m {
410            v.clone()
411        } else {
412            unreachable!()
413        }
414    }
415
416    fn fonts(&self) -> Arc<IncrFontPack> {
417        // cache the index
418        let sz = &self.meta_indices[MetaIndices::Font as usize];
419        let sz = sz.get_or_init(|| {
420            let mut sz = usize::MAX; // will panic if not found
421            for (idx, m) in self.metadata.iter().enumerate() {
422                if let ModuleMetadata::Font(_) = m {
423                    sz = idx;
424                    break;
425                }
426            }
427            sz
428        });
429
430        // get the item pack
431        let m = &self.metadata[*sz];
432        if let ModuleMetadata::Font(v) = m {
433            v.clone()
434        } else {
435            unreachable!()
436        }
437    }
438
439    fn glyphs(&self) -> Arc<IncrGlyphPack> {
440        // cache the index
441        let sz = &self.meta_indices[MetaIndices::Glyph as usize];
442        let sz = sz.get_or_init(|| {
443            let mut sz = usize::MAX; // will panic if not found
444            for (idx, m) in self.metadata.iter().enumerate() {
445                if let ModuleMetadata::Glyph(_) = m {
446                    sz = idx;
447                    break;
448                }
449            }
450            sz
451        });
452
453        // get the item pack
454        let m = &self.metadata[*sz];
455        if let ModuleMetadata::Glyph(v) = m {
456            v.clone()
457        } else {
458            unreachable!()
459        }
460    }
461
462    fn gc_items(&self) -> Option<Vec<Fingerprint>> {
463        for m in &self.metadata {
464            if let ModuleMetadata::GarbageCollection(v) = m {
465                return Some(v.clone());
466            }
467        }
468        None
469    }
470}