|
1 | 1 | // Copyright (c) Microsoft Corporation. |
2 | 2 | // Licensed under the MIT License. |
3 | 3 |
|
4 | | -use std::collections::HashMap; |
5 | | -use std::sync::Mutex; |
6 | | - |
7 | 4 | use anyhow::Result; |
8 | | -use thiserror::Error; |
9 | 5 |
|
10 | 6 | use crate::path::FilePath; |
11 | 7 |
|
12 | | -#[derive(Clone, Copy)] |
13 | | -struct Leaked(&'static [u8]); |
14 | | - |
15 | | -impl Leaked { |
16 | | - pub fn into_raw(self) -> *mut [u8] { |
17 | | - self.0 as *const _ as *mut _ |
18 | | - } |
| 8 | +pub struct Loader { |
| 9 | + loaded: elsa::sync::FrozenMap<FilePath, Box<[u8]>>, |
19 | 10 | } |
20 | 11 |
|
21 | | -impl From<Vec<u8>> for Leaked { |
22 | | - fn from(data: Vec<u8>) -> Self { |
23 | | - let data = Box::leak(data.into_boxed_slice()); |
24 | | - Leaked(data) |
| 12 | +impl Default for Loader { |
| 13 | + fn default() -> Self { |
| 14 | + Self { |
| 15 | + // sync version doesn't have a Default impl |
| 16 | + loaded: elsa::sync::FrozenMap::new(), |
| 17 | + } |
25 | 18 | } |
26 | 19 | } |
27 | 20 |
|
28 | | -#[derive(Default)] |
29 | | -pub struct Loader { |
30 | | - loaded: Mutex<HashMap<FilePath, Leaked>>, |
31 | | -} |
32 | | - |
33 | 21 | impl Loader { |
34 | 22 | pub fn new() -> Self { |
35 | 23 | Self::default() |
36 | 24 | } |
37 | 25 |
|
38 | 26 | pub fn load(&self, path: &FilePath) -> Result<&[u8]> { |
39 | | - if let Some(data) = self.get(path)? { |
40 | | - Ok(data) |
41 | | - } else { |
42 | | - self.load_new(path) |
43 | | - } |
44 | | - } |
45 | | - |
46 | | - fn load_new(&self, path: &FilePath) -> Result<&[u8]> { |
47 | | - let mut loaded = self.loaded.lock().map_err(|_| LoaderError::PoisonedMutex)?; |
48 | | - let data = std::fs::read(path)?; |
49 | | - let leaked = Leaked::from(data); |
50 | | - loaded.insert(path.clone(), leaked); |
| 27 | + // Note: if we ever have this callable in parallel from |
| 28 | + // multiple threads, we should use some kind of |
| 29 | + // lock to prevent loading the same file multiple times. |
51 | 30 |
|
52 | | - Ok(leaked.0) |
53 | | - } |
54 | | - |
55 | | - pub fn get(&self, path: &FilePath) -> Result<Option<&[u8]>> { |
56 | | - let loaded = self.loaded.lock().map_err(|_| LoaderError::PoisonedMutex)?; |
57 | | - |
58 | | - let data = loaded.get(path).map(|l| l.0); |
59 | | - |
60 | | - Ok(data) |
61 | | - } |
62 | | -} |
63 | | - |
64 | | -impl Drop for Loader { |
65 | | - fn drop(&mut self) { |
66 | | - if let Ok(mut loaded) = self.loaded.lock() { |
67 | | - for (_, leaked) in loaded.drain() { |
68 | | - unsafe { |
69 | | - let raw = leaked.into_raw(); |
70 | | - let owned = Box::from_raw(raw); |
71 | | - drop(owned); |
72 | | - } |
73 | | - } |
74 | | - |
75 | | - debug_assert!(loaded.is_empty()); |
| 31 | + if let Some(data) = self.loaded.get(path) { |
| 32 | + return Ok(data); |
76 | 33 | } |
77 | | - } |
78 | | -} |
79 | 34 |
|
80 | | -#[derive(Error, Debug)] |
81 | | -pub enum LoaderError { |
82 | | - #[error("internal mutex poisoned")] |
83 | | - PoisonedMutex, |
| 35 | + let data: Box<[u8]> = std::fs::read(path)?.into(); |
| 36 | + Ok(self.loaded.insert(path.clone(), data)) |
| 37 | + } |
84 | 38 | } |
0 commit comments