1use crate::{FontId, GlyphId, Pixels, PlatformTextSystem, Point, SharedString, Size, point, px};
2use collections::FxHashMap;
3use parking_lot::{Mutex, RwLock, RwLockUpgradableReadGuard};
4use smallvec::SmallVec;
5use std::{
6 borrow::Borrow,
7 hash::{Hash, Hasher},
8 ops::Range,
9 sync::{
10 Arc,
11 atomic::{AtomicU64, Ordering},
12 },
13};
14
15use super::LineWrapper;
16
17#[derive(Default, Debug)]
19pub struct LineLayout {
20 pub font_size: Pixels,
22 pub width: Pixels,
24 pub ascent: Pixels,
26 pub descent: Pixels,
28 pub runs: Vec<ShapedRun>,
30 pub len: usize,
32}
33
34#[derive(Debug, Clone)]
36pub struct ShapedRun {
37 pub font_id: FontId,
39 pub glyphs: Vec<ShapedGlyph>,
41}
42
43#[derive(Clone, Debug)]
45pub struct ShapedGlyph {
46 pub id: GlyphId,
48
49 pub position: Point<Pixels>,
51
52 pub index: usize,
54
55 pub is_emoji: bool,
57}
58
59impl LineLayout {
60 pub fn index_for_x(&self, x: Pixels) -> Option<usize> {
62 if x >= self.width {
63 None
64 } else {
65 for run in self.runs.iter().rev() {
66 for glyph in run.glyphs.iter().rev() {
67 if glyph.position.x <= x {
68 return Some(glyph.index);
69 }
70 }
71 }
72 Some(0)
73 }
74 }
75
76 pub fn closest_index_for_x(&self, x: Pixels) -> usize {
79 let mut prev_index = 0;
80 let mut prev_x = px(0.);
81
82 for run in self.runs.iter() {
83 for glyph in run.glyphs.iter() {
84 if glyph.position.x >= x {
85 if glyph.position.x - x < x - prev_x {
86 return glyph.index;
87 } else {
88 return prev_index;
89 }
90 }
91 prev_index = glyph.index;
92 prev_x = glyph.position.x;
93 }
94 }
95
96 if self.len == 1 {
97 if x > self.width / 2. {
98 return 1;
99 } else {
100 return 0;
101 }
102 }
103
104 self.len
105 }
106
107 pub fn x_for_index(&self, index: usize) -> Pixels {
109 for run in &self.runs {
110 for glyph in &run.glyphs {
111 if glyph.index >= index {
112 return glyph.position.x;
113 }
114 }
115 }
116 self.width
117 }
118
119 pub fn font_id_for_index(&self, index: usize) -> Option<FontId> {
121 for run in &self.runs {
122 for glyph in &run.glyphs {
123 if glyph.index >= index {
124 return Some(run.font_id);
125 }
126 }
127 }
128 None
129 }
130
131 fn compute_wrap_boundaries(
132 &self,
133 text: &str,
134 wrap_width: Pixels,
135 max_lines: Option<usize>,
136 ) -> SmallVec<[WrapBoundary; 1]> {
137 let mut boundaries = SmallVec::new();
138 let mut first_non_whitespace_ix = None;
139 let mut last_candidate_ix = None;
140 let mut last_candidate_x = px(0.);
141 let mut last_boundary = WrapBoundary {
142 run_ix: 0,
143 glyph_ix: 0,
144 };
145 let mut last_boundary_x = px(0.);
146 let mut prev_ch = '\0';
147 let mut glyphs = self
148 .runs
149 .iter()
150 .enumerate()
151 .flat_map(move |(run_ix, run)| {
152 run.glyphs.iter().enumerate().map(move |(glyph_ix, glyph)| {
153 let character = text[glyph.index..].chars().next().unwrap();
154 (
155 WrapBoundary { run_ix, glyph_ix },
156 character,
157 glyph.position.x,
158 )
159 })
160 })
161 .peekable();
162
163 while let Some((boundary, ch, x)) = glyphs.next() {
164 if ch == '\n' {
165 continue;
166 }
167
168 if LineWrapper::is_word_char(ch) {
171 if prev_ch == ' ' && ch != ' ' && first_non_whitespace_ix.is_some() {
172 last_candidate_ix = Some(boundary);
173 last_candidate_x = x;
174 }
175 } else {
176 if ch != ' ' && first_non_whitespace_ix.is_some() {
177 last_candidate_ix = Some(boundary);
178 last_candidate_x = x;
179 }
180 }
181
182 if ch != ' ' && first_non_whitespace_ix.is_none() {
183 first_non_whitespace_ix = Some(boundary);
184 }
185
186 let next_x = glyphs.peek().map_or(self.width, |(_, _, x)| *x);
187 let width = next_x - last_boundary_x;
188
189 if width > wrap_width && boundary > last_boundary {
190 if let Some(max_lines) = max_lines
192 && boundaries.len() >= max_lines - 1
193 {
194 break;
195 }
196
197 if let Some(last_candidate_ix) = last_candidate_ix.take() {
198 last_boundary = last_candidate_ix;
199 last_boundary_x = last_candidate_x;
200 } else {
201 last_boundary = boundary;
202 last_boundary_x = x;
203 }
204 boundaries.push(last_boundary);
205 }
206 prev_ch = ch;
207 }
208
209 boundaries
210 }
211}
212
213#[derive(Default, Debug)]
215pub struct WrappedLineLayout {
216 pub unwrapped_layout: Arc<LineLayout>,
218
219 pub wrap_boundaries: SmallVec<[WrapBoundary; 1]>,
221
222 pub wrap_width: Option<Pixels>,
224}
225
226#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
228pub struct WrapBoundary {
229 pub run_ix: usize,
231 pub glyph_ix: usize,
233}
234
235impl WrappedLineLayout {
236 #[allow(clippy::len_without_is_empty)]
238 pub fn len(&self) -> usize {
239 self.unwrapped_layout.len
240 }
241
242 pub fn width(&self) -> Pixels {
244 self.wrap_width
245 .unwrap_or(Pixels::MAX)
246 .min(self.unwrapped_layout.width)
247 }
248
249 pub fn size(&self, line_height: Pixels) -> Size<Pixels> {
252 Size {
253 width: self.width(),
254 height: line_height * (self.wrap_boundaries.len() + 1),
255 }
256 }
257
258 pub fn ascent(&self) -> Pixels {
260 self.unwrapped_layout.ascent
261 }
262
263 pub fn descent(&self) -> Pixels {
265 self.unwrapped_layout.descent
266 }
267
268 pub fn wrap_boundaries(&self) -> &[WrapBoundary] {
270 &self.wrap_boundaries
271 }
272
273 pub fn font_size(&self) -> Pixels {
275 self.unwrapped_layout.font_size
276 }
277
278 pub fn runs(&self) -> &[ShapedRun] {
280 &self.unwrapped_layout.runs
281 }
282
283 pub fn index_for_position(
287 &self,
288 position: Point<Pixels>,
289 line_height: Pixels,
290 ) -> Result<usize, usize> {
291 self._index_for_position(position, line_height, false)
292 }
293
294 pub fn closest_index_for_position(
300 &self,
301 position: Point<Pixels>,
302 line_height: Pixels,
303 ) -> Result<usize, usize> {
304 self._index_for_position(position, line_height, true)
305 }
306
307 fn _index_for_position(
308 &self,
309 mut position: Point<Pixels>,
310 line_height: Pixels,
311 closest: bool,
312 ) -> Result<usize, usize> {
313 let wrapped_line_ix = (position.y / line_height) as usize;
314
315 let wrapped_line_start_index;
316 let wrapped_line_start_x;
317 if wrapped_line_ix > 0 {
318 let Some(line_start_boundary) = self.wrap_boundaries.get(wrapped_line_ix - 1) else {
319 return Err(0);
320 };
321 let run = &self.unwrapped_layout.runs[line_start_boundary.run_ix];
322 let glyph = &run.glyphs[line_start_boundary.glyph_ix];
323 wrapped_line_start_index = glyph.index;
324 wrapped_line_start_x = glyph.position.x;
325 } else {
326 wrapped_line_start_index = 0;
327 wrapped_line_start_x = Pixels::ZERO;
328 };
329
330 let wrapped_line_end_index;
331 let wrapped_line_end_x;
332 if wrapped_line_ix < self.wrap_boundaries.len() {
333 let next_wrap_boundary_ix = wrapped_line_ix;
334 let next_wrap_boundary = self.wrap_boundaries[next_wrap_boundary_ix];
335 let run = &self.unwrapped_layout.runs[next_wrap_boundary.run_ix];
336 let glyph = &run.glyphs[next_wrap_boundary.glyph_ix];
337 wrapped_line_end_index = glyph.index;
338 wrapped_line_end_x = glyph.position.x;
339 } else {
340 wrapped_line_end_index = self.unwrapped_layout.len;
341 wrapped_line_end_x = self.unwrapped_layout.width;
342 };
343
344 let mut position_in_unwrapped_line = position;
345 position_in_unwrapped_line.x += wrapped_line_start_x;
346 if position_in_unwrapped_line.x < wrapped_line_start_x {
347 Err(wrapped_line_start_index)
348 } else if position_in_unwrapped_line.x >= wrapped_line_end_x {
349 Err(wrapped_line_end_index)
350 } else {
351 if closest {
352 Ok(self
353 .unwrapped_layout
354 .closest_index_for_x(position_in_unwrapped_line.x))
355 } else {
356 Ok(self
357 .unwrapped_layout
358 .index_for_x(position_in_unwrapped_line.x)
359 .unwrap())
360 }
361 }
362 }
363
364 pub fn position_for_index(&self, index: usize, line_height: Pixels) -> Option<Point<Pixels>> {
366 let mut line_start_ix = 0;
367 let mut line_end_indices = self
368 .wrap_boundaries
369 .iter()
370 .map(|wrap_boundary| {
371 let run = &self.unwrapped_layout.runs[wrap_boundary.run_ix];
372 let glyph = &run.glyphs[wrap_boundary.glyph_ix];
373 glyph.index
374 })
375 .chain([self.len()])
376 .enumerate();
377 for (ix, line_end_ix) in line_end_indices {
378 let line_y = ix as f32 * line_height;
379 if index < line_start_ix {
380 break;
381 } else if index > line_end_ix {
382 line_start_ix = line_end_ix;
383 continue;
384 } else {
385 let line_start_x = self.unwrapped_layout.x_for_index(line_start_ix);
386 let x = self.unwrapped_layout.x_for_index(index) - line_start_x;
387 return Some(point(x, line_y));
388 }
389 }
390
391 None
392 }
393}
394
395const GLOBAL_CACHE_MAX_ENTRIES: usize = 10_000;
396
397struct GlobalCacheEntry<T> {
398 value: T,
399 last_access: AtomicU64,
400}
401
402pub(crate) struct GlobalLineLayoutCache {
403 lines: RwLock<FxHashMap<Arc<CacheKey>, GlobalCacheEntry<Arc<LineLayout>>>>,
404 wrapped_lines: RwLock<FxHashMap<Arc<CacheKey>, GlobalCacheEntry<Arc<WrappedLineLayout>>>>,
405 access_counter: AtomicU64,
406}
407
408impl GlobalLineLayoutCache {
409 pub fn new() -> Self {
410 Self {
411 lines: RwLock::new(FxHashMap::default()),
412 wrapped_lines: RwLock::new(FxHashMap::default()),
413 access_counter: AtomicU64::new(0),
414 }
415 }
416
417 fn get_line(&self, key: &dyn AsCacheKeyRef) -> Option<Arc<LineLayout>> {
418 let lines = self.lines.read();
419 if let Some(entry) = lines.get(key) {
420 entry
422 .last_access
423 .store(self.access_counter.fetch_add(1, Ordering::Relaxed), Ordering::Relaxed);
424 Some(entry.value.clone())
425 } else {
426 None
427 }
428 }
429
430 fn insert_line(&self, key: Arc<CacheKey>, layout: Arc<LineLayout>) {
431 let mut lines = self.lines.write();
432 if lines.len() >= GLOBAL_CACHE_MAX_ENTRIES {
433 Self::evict_oldest(&mut lines);
434 }
435 lines.insert(key, GlobalCacheEntry {
436 value: layout,
437 last_access: AtomicU64::new(self.access_counter.fetch_add(1, Ordering::Relaxed)),
438 });
439 }
440
441 fn get_wrapped_line(&self, key: &dyn AsCacheKeyRef) -> Option<Arc<WrappedLineLayout>> {
442 let wrapped = self.wrapped_lines.read();
443 if let Some(entry) = wrapped.get(key) {
444 entry
445 .last_access
446 .store(self.access_counter.fetch_add(1, Ordering::Relaxed), Ordering::Relaxed);
447 Some(entry.value.clone())
448 } else {
449 None
450 }
451 }
452
453 fn insert_wrapped_line(&self, key: Arc<CacheKey>, layout: Arc<WrappedLineLayout>) {
454 let mut wrapped = self.wrapped_lines.write();
455 if wrapped.len() >= GLOBAL_CACHE_MAX_ENTRIES {
456 Self::evict_oldest(&mut wrapped);
457 }
458 wrapped.insert(key, GlobalCacheEntry {
459 value: layout,
460 last_access: AtomicU64::new(self.access_counter.fetch_add(1, Ordering::Relaxed)),
461 });
462 }
463
464 fn evict_oldest<V>(map: &mut FxHashMap<Arc<CacheKey>, GlobalCacheEntry<V>>) {
465 let half = map.len() / 2;
466 let mut entries: Vec<_> = map
467 .keys()
468 .map(|k| (k.clone(), map.get(k).unwrap().last_access.load(Ordering::Relaxed)))
469 .collect();
470 entries.sort_by_key(|(_, access)| *access);
471 for (key, _) in entries.into_iter().take(half) {
472 map.remove(&key);
473 }
474 }
475}
476
477pub(crate) struct LineLayoutCache {
478 previous_frame: Mutex<FrameCache>,
479 current_frame: RwLock<FrameCache>,
480 platform_text_system: Arc<dyn PlatformTextSystem>,
481 global_cache: Arc<GlobalLineLayoutCache>,
482}
483
484#[derive(Default)]
485struct FrameCache {
486 lines: FxHashMap<Arc<CacheKey>, Arc<LineLayout>>,
487 wrapped_lines: FxHashMap<Arc<CacheKey>, Arc<WrappedLineLayout>>,
488 used_lines: Vec<Arc<CacheKey>>,
489 used_wrapped_lines: Vec<Arc<CacheKey>>,
490}
491
492#[derive(Clone, Default)]
493pub(crate) struct LineLayoutIndex {
494 lines_index: usize,
495 wrapped_lines_index: usize,
496}
497
498impl LineLayoutCache {
499 pub fn new(
500 platform_text_system: Arc<dyn PlatformTextSystem>,
501 global_cache: Arc<GlobalLineLayoutCache>,
502 ) -> Self {
503 Self {
504 previous_frame: Mutex::default(),
505 current_frame: RwLock::default(),
506 platform_text_system,
507 global_cache,
508 }
509 }
510
511 pub fn layout_index(&self) -> LineLayoutIndex {
512 let frame = self.current_frame.read();
513 LineLayoutIndex {
514 lines_index: frame.used_lines.len(),
515 wrapped_lines_index: frame.used_wrapped_lines.len(),
516 }
517 }
518
519 pub fn reuse_layouts(&self, range: Range<LineLayoutIndex>) {
520 let mut previous_frame = &mut *self.previous_frame.lock();
521 let mut current_frame = &mut *self.current_frame.write();
522
523 for key in &previous_frame.used_lines[range.start.lines_index..range.end.lines_index] {
524 if let Some((key, line)) = previous_frame.lines.remove_entry(key) {
525 current_frame.lines.insert(key, line);
526 }
527 current_frame.used_lines.push(key.clone());
528 }
529
530 for key in &previous_frame.used_wrapped_lines
531 [range.start.wrapped_lines_index..range.end.wrapped_lines_index]
532 {
533 if let Some((key, line)) = previous_frame.wrapped_lines.remove_entry(key) {
534 current_frame.wrapped_lines.insert(key, line);
535 }
536 current_frame.used_wrapped_lines.push(key.clone());
537 }
538 }
539
540 pub fn truncate_layouts(&self, index: LineLayoutIndex) {
541 let mut current_frame = &mut *self.current_frame.write();
542 current_frame.used_lines.truncate(index.lines_index);
543 current_frame
544 .used_wrapped_lines
545 .truncate(index.wrapped_lines_index);
546 }
547
548 pub fn finish_frame(&self) {
549 let mut prev_frame = self.previous_frame.lock();
550 let mut curr_frame = self.current_frame.write();
551 std::mem::swap(&mut *prev_frame, &mut *curr_frame);
552 curr_frame.lines.clear();
553 curr_frame.wrapped_lines.clear();
554 curr_frame.used_lines.clear();
555 curr_frame.used_wrapped_lines.clear();
556 }
557
558 pub fn layout_wrapped_line<Text>(
559 &self,
560 text: Text,
561 font_size: Pixels,
562 runs: &[FontRun],
563 wrap_width: Option<Pixels>,
564 max_lines: Option<usize>,
565 ) -> Arc<WrappedLineLayout>
566 where
567 Text: AsRef<str>,
568 SharedString: From<Text>,
569 {
570 let key = &CacheKeyRef {
571 text: text.as_ref(),
572 font_size,
573 runs,
574 wrap_width,
575 force_width: None,
576 letter_spacing: None,
577 } as &dyn AsCacheKeyRef;
578
579 let current_frame = self.current_frame.upgradable_read();
580 if let Some(layout) = current_frame.wrapped_lines.get(key) {
581 return layout.clone();
582 }
583
584 let previous_frame_entry = self.previous_frame.lock().wrapped_lines.remove_entry(key);
585 if let Some((key, layout)) = previous_frame_entry {
586 let mut current_frame = RwLockUpgradableReadGuard::upgrade(current_frame);
587 current_frame
588 .wrapped_lines
589 .insert(key.clone(), layout.clone());
590 current_frame.used_wrapped_lines.push(key);
591 layout
592 } else {
593 if let Some(layout) = self.global_cache.get_wrapped_line(key) {
595 let mut current_frame = RwLockUpgradableReadGuard::upgrade(current_frame);
596 let key = Arc::new(CacheKey {
597 text: SharedString::from(text),
598 font_size,
599 runs: SmallVec::from(runs),
600 wrap_width,
601 force_width: None,
602 letter_spacing: None,
603 });
604 current_frame
605 .wrapped_lines
606 .insert(key.clone(), layout.clone());
607 current_frame.used_wrapped_lines.push(key);
608 return layout;
609 }
610
611 drop(current_frame);
612 let text = SharedString::from(text);
613 let unwrapped_layout = self.layout_line::<&SharedString>(&text, font_size, runs, None);
614 let wrap_boundaries = if let Some(wrap_width) = wrap_width {
615 unwrapped_layout.compute_wrap_boundaries(text.as_ref(), wrap_width, max_lines)
616 } else {
617 SmallVec::new()
618 };
619 let layout = Arc::new(WrappedLineLayout {
620 unwrapped_layout,
621 wrap_boundaries,
622 wrap_width,
623 });
624 let key = Arc::new(CacheKey {
625 text,
626 font_size,
627 runs: SmallVec::from(runs),
628 wrap_width,
629 force_width: None,
630 letter_spacing: None,
631 });
632
633 let mut current_frame = self.current_frame.write();
634 current_frame
635 .wrapped_lines
636 .insert(key.clone(), layout.clone());
637 current_frame.used_wrapped_lines.push(key.clone());
638 self.global_cache.insert_wrapped_line(key, layout.clone());
639
640 layout
641 }
642 }
643
644 pub fn layout_line<Text>(
645 &self,
646 text: Text,
647 font_size: Pixels,
648 runs: &[FontRun],
649 force_width: Option<Pixels>,
650 ) -> Arc<LineLayout>
651 where
652 Text: AsRef<str>,
653 SharedString: From<Text>,
654 {
655 self.layout_line_with_spacing(text, font_size, runs, force_width, None)
656 }
657
658 pub fn layout_line_with_spacing<Text>(
659 &self,
660 text: Text,
661 font_size: Pixels,
662 runs: &[FontRun],
663 force_width: Option<Pixels>,
664 letter_spacing: Option<Pixels>,
665 ) -> Arc<LineLayout>
666 where
667 Text: AsRef<str>,
668 SharedString: From<Text>,
669 {
670 let key = &CacheKeyRef {
671 text: text.as_ref(),
672 font_size,
673 runs,
674 wrap_width: None,
675 force_width,
676 letter_spacing,
677 } as &dyn AsCacheKeyRef;
678
679 let current_frame = self.current_frame.upgradable_read();
680 if let Some(layout) = current_frame.lines.get(key) {
681 return layout.clone();
682 }
683
684 let mut current_frame = RwLockUpgradableReadGuard::upgrade(current_frame);
685 if let Some((key, layout)) = self.previous_frame.lock().lines.remove_entry(key) {
686 current_frame.lines.insert(key.clone(), layout.clone());
687 current_frame.used_lines.push(key);
688 return layout;
689 }
690
691 if let Some(layout) = self.global_cache.get_line(key) {
693 let key = Arc::new(CacheKey {
694 text: SharedString::from(text),
695 font_size,
696 runs: SmallVec::from(runs),
697 wrap_width: None,
698 force_width,
699 letter_spacing,
700 });
701 current_frame.lines.insert(key.clone(), layout.clone());
702 current_frame.used_lines.push(key);
703 return layout;
704 }
705
706 let text = SharedString::from(text);
707 let mut layout = self
708 .platform_text_system
709 .layout_line(&text, font_size, runs);
710
711 if let Some(force_width) = force_width {
712 let mut glyph_pos = 0;
713 for run in layout.runs.iter_mut() {
714 for glyph in run.glyphs.iter_mut() {
715 if (glyph.position.x - glyph_pos * force_width).abs() > px(1.) {
716 glyph.position.x = glyph_pos * force_width;
717 }
718 glyph_pos += 1;
719 }
720 }
721 }
722
723 if let Some(spacing) = letter_spacing {
724 let mut glyph_index: usize = 0;
725 for run in layout.runs.iter_mut() {
726 for glyph in run.glyphs.iter_mut() {
727 glyph.position.x = glyph.position.x + spacing * glyph_index as f32;
728 glyph_index += 1;
729 }
730 }
731 let total_glyphs = glyph_index;
732 if total_glyphs > 1 {
733 layout.width = layout.width + spacing * (total_glyphs - 1) as f32;
734 }
735 }
736
737 let key = Arc::new(CacheKey {
738 text,
739 font_size,
740 runs: SmallVec::from(runs),
741 wrap_width: None,
742 force_width,
743 letter_spacing,
744 });
745 let layout = Arc::new(layout);
746 current_frame.lines.insert(key.clone(), layout.clone());
747 current_frame.used_lines.push(key.clone());
748 self.global_cache.insert_line(key, layout.clone());
749 layout
750 }
751}
752
753#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
755pub struct FontRun {
756 pub(crate) len: usize,
757 pub(crate) font_id: FontId,
758}
759
760trait AsCacheKeyRef {
761 fn as_cache_key_ref(&self) -> CacheKeyRef<'_>;
762}
763
764#[derive(Clone, Debug, Eq)]
765struct CacheKey {
766 text: SharedString,
767 font_size: Pixels,
768 runs: SmallVec<[FontRun; 1]>,
769 wrap_width: Option<Pixels>,
770 force_width: Option<Pixels>,
771 letter_spacing: Option<Pixels>,
772}
773
774#[derive(Copy, Clone, PartialEq, Eq, Hash)]
775struct CacheKeyRef<'a> {
776 text: &'a str,
777 font_size: Pixels,
778 runs: &'a [FontRun],
779 wrap_width: Option<Pixels>,
780 force_width: Option<Pixels>,
781 letter_spacing: Option<Pixels>,
782}
783
784impl PartialEq for dyn AsCacheKeyRef + '_ {
785 fn eq(&self, other: &dyn AsCacheKeyRef) -> bool {
786 self.as_cache_key_ref() == other.as_cache_key_ref()
787 }
788}
789
790impl Eq for dyn AsCacheKeyRef + '_ {}
791
792impl Hash for dyn AsCacheKeyRef + '_ {
793 fn hash<H: Hasher>(&self, state: &mut H) {
794 self.as_cache_key_ref().hash(state)
795 }
796}
797
798impl AsCacheKeyRef for CacheKey {
799 fn as_cache_key_ref(&self) -> CacheKeyRef<'_> {
800 CacheKeyRef {
801 text: &self.text,
802 font_size: self.font_size,
803 runs: self.runs.as_slice(),
804 wrap_width: self.wrap_width,
805 force_width: self.force_width,
806 letter_spacing: self.letter_spacing,
807 }
808 }
809}
810
811impl PartialEq for CacheKey {
812 fn eq(&self, other: &Self) -> bool {
813 self.as_cache_key_ref().eq(&other.as_cache_key_ref())
814 }
815}
816
817impl Hash for CacheKey {
818 fn hash<H: Hasher>(&self, state: &mut H) {
819 self.as_cache_key_ref().hash(state);
820 }
821}
822
823impl<'a> Borrow<dyn AsCacheKeyRef + 'a> for Arc<CacheKey> {
824 fn borrow(&self) -> &(dyn AsCacheKeyRef + 'a) {
825 self.as_ref() as &dyn AsCacheKeyRef
826 }
827}
828
829impl AsCacheKeyRef for CacheKeyRef<'_> {
830 fn as_cache_key_ref(&self) -> CacheKeyRef<'_> {
831 *self
832 }
833}