Skip to content

Commit 86154a3

Browse files
committed
Add use_symbols! to enable using Lisp symbols w/o repeated interning
1 parent f171675 commit 86154a3

File tree

6 files changed

+70
-47
lines changed

6 files changed

+70
-47
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
66
## [Unreleased]
77
- Added `Env::define_error` and `Env::signal` to simplify the process of signaling Lisp errors.
88
- Added `OnceGlobalRef`, which eases the initialization of static references to long-lived Lisp values.
9+
- Added `use_symbols!`, which enables module code to use Lisp symbols without repeatedly interning them.
910
- Raised the minimum supported Rust version to 1.45.
1011

1112
## [0.16.2] - 2021-03-04

src/global.rs

Lines changed: 49 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -95,12 +95,6 @@ impl<'e> IntoLisp<'e> for &'e GlobalRef {
9595
}
9696
}
9797

98-
impl<'e> IntoLisp<'e> for &'e OnceGlobalRef {
99-
#[inline(always)]
100-
fn into_lisp(self, env: &'e Env) -> Result<Value<'e>> {
101-
Ok(self.bind(env))
102-
}
103-
}
10498

10599
impl<'e> Value<'e> {
106100
/// Creates a new [`GlobalRef`] for this value.
@@ -112,10 +106,50 @@ impl<'e> Value<'e> {
112106
}
113107
}
114108

109+
/// Declares global references. These will be initialized when the module is loaded.
110+
#[doc(hidden)]
111+
#[macro_export]
112+
macro_rules! global_refs {
113+
($($name:ident)*) => {
114+
$(
115+
#[allow(non_upper_case_globals)]
116+
pub static $name: &'static $crate::OnceGlobalRef = {
117+
static X: $crate::OnceGlobalRef = $crate::OnceGlobalRef::new();
118+
&X
119+
};
120+
)*
121+
};
122+
($registrator_name:ident ($init_method:ident) =>
123+
$(
124+
$name:ident $( => $lisp_name:expr )?
125+
)*
126+
) => {
127+
$crate::global_refs! {
128+
$($name)*
129+
}
130+
131+
#[$crate::deps::ctor::ctor]
132+
fn $registrator_name() {
133+
$crate::init::__PRE_INIT__.try_lock()
134+
.expect("Failed to acquire a write lock on the list of initializers")
135+
.push(::std::boxed::Box::new(|env| {
136+
$(
137+
#[allow(unused_variables)]
138+
let name = $crate::deps::emacs_macros::lisp_name!($name);
139+
$( let name = $lisp_name; )?
140+
$crate::OnceGlobalRef::$init_method(&$name, env, name)?;
141+
)*
142+
Ok(())
143+
}));
144+
}
145+
};
146+
}
147+
115148
/// A [`GlobalRef`] that can be initialized once. This is useful for long-lived values that should
116-
/// be initialized when the module is loaded, such as frequently-used symbols.
149+
/// be initialized when the dynamic module is loaded. A typical use case is specifying
150+
/// frequently-used symbols, which can be done with the help of the macro [`use_symbols!`].
117151
///
118-
/// [`GlobalRef`]: struct.GlobalRef.html
152+
/// [`use_symbols`]: crate::use_symbols
119153
#[derive(Debug)]
120154
#[repr(transparent)]
121155
pub struct OnceGlobalRef {
@@ -158,6 +192,13 @@ impl OnceGlobalRef {
158192
}
159193
}
160194

195+
impl<'e> IntoLisp<'e> for &'e OnceGlobalRef {
196+
#[inline(always)]
197+
fn into_lisp(self, env: &'e Env) -> Result<Value<'e>> {
198+
Ok(self.bind(env))
199+
}
200+
}
201+
161202
impl Deref for OnceGlobalRef {
162203
type Target = GlobalRef;
163204

src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ mod value;
5252
mod types;
5353
mod error;
5454
mod call;
55+
#[macro_use]
5556
mod global;
5657
mod symbol;
5758
mod subr;
@@ -66,5 +67,6 @@ pub mod raw {
6667
/// External dependencies that are mostly used by macros instead of user code.
6768
#[doc(hidden)]
6869
pub mod deps {
70+
pub use emacs_macros;
6971
pub use ctor;
7072
}

src/macros.rs

Lines changed: 0 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -64,40 +64,6 @@ macro_rules! unsafe_raw_call_value_unprotected {
6464
};
6565
}
6666

67-
/// Declare global references. These should be initialized when the module is loaded.
68-
macro_rules! global_refs {
69-
($($name:ident)*) => {
70-
$(pub static $name: &'static $crate::global::OnceGlobalRef = {
71-
static x: $crate::global::OnceGlobalRef = $crate::global::OnceGlobalRef::new();
72-
&x
73-
};)*
74-
};
75-
($registrator_name:ident ($init_method:ident) =>
76-
$(
77-
$name:ident $( => $lisp_name:expr )?
78-
)*
79-
) => {
80-
global_refs! {
81-
$($name)*
82-
}
83-
84-
#[$crate::deps::ctor::ctor]
85-
fn $registrator_name() {
86-
$crate::init::__PRE_INIT__.try_lock()
87-
.expect("Failed to acquire a write lock on the list of initializers")
88-
.push(Box::new(|env| {
89-
$(
90-
#[allow(unused_variables)]
91-
let name = ::emacs_macros::lisp_name!($name);
92-
$( let name = $lisp_name; )?
93-
$crate::global::OnceGlobalRef::$init_method(&$name, env, name)?;
94-
)*
95-
Ok(())
96-
}));
97-
}
98-
};
99-
}
100-
10167
/// Declares that this module is GPL-compatible. Emacs will not load it otherwise.
10268
#[macro_export]
10369
#[allow(non_snake_case)]

src/subr.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
#![allow(non_upper_case_globals)]
2-
31
global_refs! {common(init_to_function) =>
42
cons car cdr
53
vector make_vector

src/symbol.rs

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,23 @@
1-
#![allow(non_upper_case_globals)]
2-
31
use crate::{Env, Result, Value, global::{GlobalRef, OnceGlobalRef}};
42

5-
global_refs! {common(init_to_symbol) =>
3+
/// Defines static [`&OnceGlobalRef`] variables that point to corresponding Lisp symbols.
4+
///
5+
/// This macro accepts a space-separated list of identifiers, and determine the Lisp symbol names by
6+
/// replacing underscores with hyphens.
7+
///
8+
/// It can be used only once per Rust `mod`.
9+
///
10+
/// [`&OnceGlobalRef`]: OnceGlobalRef
11+
#[macro_export]
12+
macro_rules! use_symbols {
13+
($( $name:ident $( => $lisp_name:expr )? )*) => {
14+
$crate::global_refs! {__emrs_init_global_refs_to_symbols__(init_to_symbol) =>
15+
$( $name $( => $lisp_name )? )*
16+
}
17+
}
18+
}
19+
20+
use_symbols! {
621
nil t
722
error
823
rust_error

0 commit comments

Comments
 (0)