diff --git a/Cargo.lock b/Cargo.lock index 114bec2..8c1f7fc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -23,6 +23,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "aliasable" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd" + [[package]] name = "allocator-api2" version = "0.2.18" @@ -301,6 +307,12 @@ dependencies = [ "allocator-api2", ] +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + [[package]] name = "hermit-abi" version = "0.3.3" @@ -327,6 +339,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + [[package]] name = "itertools" version = "0.13.0" @@ -412,6 +433,31 @@ version = "11.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" +[[package]] +name = "ouroboros" +version = "0.18.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "944fa20996a25aded6b4795c6d63f10014a7a83f8be9828a11860b08c5fc4a67" +dependencies = [ + "aliasable", + "ouroboros_macro", + "static_assertions", +] + +[[package]] +name = "ouroboros_macro" +version = "0.18.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39b0deead1528fd0e5947a8546a9642a9777c25f6e1e26f34c97b204bbb465bd" +dependencies = [ + "heck", + "itertools 0.12.1", + "proc-macro2", + "proc-macro2-diagnostics", + "quote", + "syn", +] + [[package]] name = "outref" version = "0.5.1" @@ -449,6 +495,19 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "proc-macro2-diagnostics" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "version_check", + "yansi", +] + [[package]] name = "quote" version = "1.0.37" @@ -557,6 +616,7 @@ dependencies = [ "dyn-clone", "itertools 0.13.0", "memchr", + "ouroboros", "regex", "rustc-hash", "serde", @@ -965,6 +1025,12 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" +[[package]] +name = "yansi" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" + [[package]] name = "zerocopy" version = "0.7.35" diff --git a/Cargo.toml b/Cargo.toml index dbbf26f..86959e8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,7 +37,7 @@ rustc-hash = "2.1.0" dashmap = "6.1.0" memchr = "2.7.4" itertools = "0.13" - +ouroboros = "0.18.4" codspeed-criterion-compat = { version = "2.7.2", default-features = false, optional = true } static_assertions = "1.1.0" diff --git a/src/cached_source.rs b/src/cached_source.rs index a27af63..7e3fbe6 100644 --- a/src/cached_source.rs +++ b/src/cached_source.rs @@ -49,40 +49,60 @@ use crate::{ /// "Hello World\nconsole.log('test');\nconsole.log('test2');\nHello2\n" /// ); /// ``` -pub struct CachedSource { + +pub struct CachedSource { + inner: CachedSourceInner, +} + +#[ouroboros::self_referencing] +pub struct CachedSourceInner { inner: Arc, + #[not_covariant] + #[borrows(inner)] + cached_rope: Arc>>, cached_hash: Arc>, cached_maps: Arc, BuildHasherDefault>>, } +impl CachedSource { + fn get_rope(&self) -> &Rope<'_> { + self + .inner + .with(|cache| cache.cached_rope.get_or_init(|| cache.inner.rope())) + } +} + impl CachedSource { /// Create a [CachedSource] with the original [Source]. pub fn new(inner: T) -> Self { Self { - inner: Arc::new(inner), - cached_hash: Default::default(), - cached_maps: Default::default(), + inner: CachedSourceInner::new( + Arc::new(inner), + |_| Default::default(), + Default::default(), + Default::default(), + ), } } /// Get the original [Source]. pub fn original(&self) -> &T { - &self.inner + self.inner.borrow_inner() } } impl Source for CachedSource { fn source(&self) -> Cow { - self.inner.source() + Cow::Owned(self.get_rope().to_string()) } fn rope(&self) -> Rope<'_> { - self.inner.rope() + self.get_rope().clone() } fn buffer(&self) -> Cow<[u8]> { - self.inner.buffer() + self.inner.borrow_inner().buffer() } fn size(&self) -> usize { @@ -90,17 +110,20 @@ impl Source for CachedSource { } fn map(&self, options: &MapOptions) -> Option { - if let Some(map) = self.cached_maps.get(options) { + if let Some(map) = self.inner.borrow_cached_maps().get(options) { map.clone() } else { - let map = self.inner.map(options); - self.cached_maps.insert(options.clone(), map.clone()); + let map = self.inner.borrow_inner().map(options); + self + .inner + .borrow_cached_maps() + .insert(options.clone(), map.clone()); map } } fn to_writer(&self, writer: &mut dyn std::io::Write) -> std::io::Result<()> { - self.inner.to_writer(writer) + self.inner.borrow_inner().to_writer(writer) } } @@ -114,7 +137,7 @@ impl StreamChunks on_source: crate::helpers::OnSource<'_, 'a>, on_name: crate::helpers::OnName<'_, 'a>, ) -> crate::helpers::GeneratedInfo { - let cached_map = self.cached_maps.entry(options.clone()); + let cached_map = self.inner.borrow_cached_maps().entry(options.clone()); match cached_map { Entry::Occupied(entry) => { let source = self.rope(); @@ -138,7 +161,7 @@ impl StreamChunks } Entry::Vacant(entry) => { let (generated_info, map) = stream_and_get_source_and_map( - &self.inner as &T, + self.inner.borrow_inner() as &T, options, on_chunk, on_source, @@ -153,19 +176,21 @@ impl StreamChunks impl Clone for CachedSource { fn clone(&self) -> Self { - Self { - inner: self.inner.clone(), - cached_hash: self.cached_hash.clone(), - cached_maps: self.cached_maps.clone(), - } + // Self { + // inner: self.inner.clone(), + // cached_rope: Default::default(), + // cached_hash: self.cached_hash.clone(), + // cached_maps: self.cached_maps.clone(), + // } + todo!() } } impl Hash for CachedSource { fn hash(&self, state: &mut H) { - (self.cached_hash.get_or_init(|| { + (self.inner.borrow_cached_hash().get_or_init(|| { let mut hasher = FxHasher::default(); - self.inner.hash(&mut hasher); + self.original().hash(&mut hasher); hasher.finish() })) .hash(state); @@ -174,7 +199,7 @@ impl Hash for CachedSource { impl PartialEq for CachedSource { fn eq(&self, other: &Self) -> bool { - self.inner == other.inner + self.inner.borrow_inner() == other.inner.borrow_inner() } } @@ -186,9 +211,12 @@ impl std::fmt::Debug for CachedSource { f: &mut std::fmt::Formatter<'_>, ) -> Result<(), std::fmt::Error> { f.debug_struct("CachedSource") - .field("inner", self.inner.as_ref()) - .field("cached_hash", self.cached_hash.as_ref()) - .field("cached_maps", &(!self.cached_maps.is_empty())) + .field("inner", self.inner.borrow_inner().as_ref()) + .field("cached_hash", self.inner.borrow_cached_hash().as_ref()) + .field( + "cached_maps", + &(!self.inner.borrow_cached_maps().is_empty()), + ) .finish() } } @@ -236,7 +264,12 @@ mod tests { source.map(&map_options); assert_eq!( - *clone.cached_maps.get(&map_options).unwrap().value(), + *clone + .inner + .borrow_cached_maps() + .get(&map_options) + .unwrap() + .value(), source.map(&map_options) ); }