Skip to content

Commit 0c4d130

Browse files
committed
Use Box::{leak,from_raw} to create self-reference for Pattern parser
1 parent 816560d commit 0c4d130

File tree

2 files changed

+28
-25
lines changed

2 files changed

+28
-25
lines changed

spdlog-macros/Cargo.toml

-1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,5 @@ proc-macro = true
1717
nom = "7.1.1"
1818
proc-macro2 = "1.0.47"
1919
quote = "1.0.21"
20-
self_cell = "1.0.1"
2120
spdlog-internal = { version = "=0.1.0", path = "../spdlog-internal" }
2221
syn = { version = "2.0.38", features = ["full"] }

spdlog-macros/src/pattern/mod.rs

+28-24
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ mod synthesis;
22

33
use proc_macro2::{Span, TokenStream};
44
use quote::quote;
5-
use self_cell::self_cell;
65
use spdlog_internal::pattern_parser::{
76
check_custom_pattern_names, parse::Template, PatternRegistry, Result,
87
};
@@ -71,26 +70,18 @@ pub fn runtime_pattern_impl(runtime_pattern: RuntimePattern) -> Result<TokenStre
7170
7271
pub struct Pattern {
7372
/// The template string included in the pattern.
74-
template: TemplateSelfRef,
73+
template: Option<(&'static String, Template<'static>)>,
7574
/// Any user-provided pattern-to-formatter mapping.
7675
custom_patterns: CustomPatterns,
7776
}
7877

79-
self_cell! {
80-
pub struct TemplateSelfRef {
81-
owner: String,
82-
#[covariant]
83-
dependent: Template,
84-
}
85-
}
86-
8778
impl Pattern {
8879
fn custom_patterns(&self) -> impl IntoIterator<Item = &(Ident, Path)> {
8980
self.custom_patterns.0.iter()
9081
}
9182

9283
fn template(&self) -> &Template {
93-
self.template.borrow_dependent()
84+
&self.template.as_ref().unwrap().1
9485
}
9586
}
9687

@@ -100,20 +91,33 @@ impl Parse for Pattern {
10091
input.parse::<Option<Token![,]>>()?;
10192
let custom_patterns = input.parse()?;
10293

103-
let ret = Pattern {
104-
template: TemplateSelfRef::try_new(template_lit.value(), |template_str| {
105-
Template::parse(template_str).map_err(|err| {
106-
syn::Error::new(
107-
// TODO: Maybe we can make a subspan for the literal for a better error
108-
// message
109-
template_lit.span(),
110-
err,
111-
)
112-
})
113-
})?,
94+
// Struct `Template` have almost no way of owning a `String`, we have to store
95+
// `template_lit` somewhere. Here we use `Box::leak` + `Box::from_raw` to create
96+
// a simple self-reference.
97+
let template_lit_leaked = Box::leak(Box::new(template_lit.value()));
98+
99+
let template = Template::parse(template_lit_leaked).map_err(|err| {
100+
syn::Error::new(
101+
// TODO: Maybe we can make a subspan for the literal for a better error message
102+
template_lit.span(),
103+
err,
104+
)
105+
})?;
106+
107+
Ok(Pattern {
108+
template: Some((template_lit_leaked, template)),
114109
custom_patterns,
115-
};
116-
Ok(ret)
110+
})
111+
}
112+
}
113+
114+
impl Drop for Pattern {
115+
fn drop(&mut self) {
116+
let (template_lit_leaked, template) = self.template.take().unwrap();
117+
// Drop the user of the leaked data first.
118+
drop(template);
119+
// Restore the ownership of the leaked `String` and then drop it.
120+
drop(unsafe { Box::from_raw(template_lit_leaked as *const String as *mut String) });
117121
}
118122
}
119123

0 commit comments

Comments
 (0)