From cb21cb00e6a5127ef8e6115a8f4e2684e5dc60ac Mon Sep 17 00:00:00 2001 From: Asuna Date: Thu, 21 Mar 2024 07:15:44 +0800 Subject: [PATCH] Use `Box::{leak,from_raw}` to create self-reference for `Pattern` parser --- spdlog-macros/Cargo.toml | 1 - spdlog-macros/src/pattern/mod.rs | 52 +++++++++++++++++--------------- 2 files changed, 28 insertions(+), 25 deletions(-) diff --git a/spdlog-macros/Cargo.toml b/spdlog-macros/Cargo.toml index 5c84af29..2c811679 100644 --- a/spdlog-macros/Cargo.toml +++ b/spdlog-macros/Cargo.toml @@ -17,6 +17,5 @@ proc-macro = true nom = "7.1.1" proc-macro2 = "1.0.47" quote = "1.0.21" -self_cell = "1.0.1" spdlog-internal = { version = "=0.1.0", path = "../spdlog-internal" } syn = { version = "2.0.38", features = ["full"] } diff --git a/spdlog-macros/src/pattern/mod.rs b/spdlog-macros/src/pattern/mod.rs index d82315b8..978be0d8 100644 --- a/spdlog-macros/src/pattern/mod.rs +++ b/spdlog-macros/src/pattern/mod.rs @@ -2,7 +2,6 @@ mod synthesis; use proc_macro2::{Span, TokenStream}; use quote::quote; -use self_cell::self_cell; use spdlog_internal::pattern_parser::{ check_custom_pattern_names, parse::Template, PatternRegistry, Result, }; @@ -71,26 +70,18 @@ pub fn runtime_pattern_impl(runtime_pattern: RuntimePattern) -> Result)>, /// Any user-provided pattern-to-formatter mapping. custom_patterns: CustomPatterns, } -self_cell! { - pub struct TemplateSelfRef { - owner: String, - #[covariant] - dependent: Template, - } -} - impl Pattern { fn custom_patterns(&self) -> impl IntoIterator { self.custom_patterns.0.iter() } fn template(&self) -> &Template { - self.template.borrow_dependent() + &self.template.as_ref().unwrap().1 } } @@ -100,20 +91,33 @@ impl Parse for Pattern { input.parse::>()?; let custom_patterns = input.parse()?; - let ret = Pattern { - template: TemplateSelfRef::try_new(template_lit.value(), |template_str| { - Template::parse(template_str).map_err(|err| { - syn::Error::new( - // TODO: Maybe we can make a subspan for the literal for a better error - // message - template_lit.span(), - err, - ) - }) - })?, + // Struct `Template` have almost no way of owning a `String`, we have to store + // `template_lit` somewhere. Here we use `Box::leak` + `Box::from_raw` to create + // a simple self-reference. + let template_lit_leaked = Box::leak(Box::new(template_lit.value())); + + let template = Template::parse(template_lit_leaked).map_err(|err| { + syn::Error::new( + // TODO: Maybe we can make a subspan for the literal for a better error message + template_lit.span(), + err, + ) + })?; + + Ok(Pattern { + template: Some((template_lit_leaked, template)), custom_patterns, - }; - Ok(ret) + }) + } +} + +impl Drop for Pattern { + fn drop(&mut self) { + let (template_lit_leaked, template) = self.template.take().unwrap(); + // Drop the user of the leaked data first. + drop(template); + // Restore the ownership of the leaked `String` and then drop it. + drop(unsafe { Box::from_raw(template_lit_leaked as *const String as *mut String) }); } }